summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--CMakeLists.txt9
-rw-r--r--clang.xcodeproj/project.pbxproj15
-rw-r--r--docs/LanguageExtensions.html340
-rw-r--r--docs/Makefile4
-rw-r--r--docs/UsersManual.html31
-rw-r--r--docs/doxygen.cfg1230
-rw-r--r--docs/doxygen.cfg.in18
-rw-r--r--docs/libIndex.html267
-rw-r--r--examples/CMakeLists.txt1
-rw-r--r--examples/Tooling/CMakeLists.txt6
-rw-r--r--examples/Tooling/ClangCheck.cpp108
-rw-r--r--examples/Tooling/Makefile24
-rw-r--r--examples/clang-interpreter/Makefile5
-rw-r--r--examples/clang-interpreter/main.cpp2
-rw-r--r--examples/wpa/Makefile9
-rw-r--r--include/clang-c/Index.h40
-rw-r--r--include/clang/AST/APValue.h8
-rw-r--r--include/clang/AST/ASTContext.h56
-rw-r--r--include/clang/AST/CanonicalType.h10
-rw-r--r--include/clang/AST/Decl.h125
-rw-r--r--include/clang/AST/DeclBase.h11
-rw-r--r--include/clang/AST/DeclCXX.h184
-rw-r--r--include/clang/AST/DeclObjC.h20
-rw-r--r--include/clang/AST/DeclTemplate.h75
-rw-r--r--include/clang/AST/Expr.h66
-rw-r--r--include/clang/AST/ExternalASTSource.h2
-rw-r--r--include/clang/AST/RecursiveASTVisitor.h17
-rw-r--r--include/clang/AST/StmtVisitor.h57
-rw-r--r--include/clang/AST/Type.h95
-rw-r--r--include/clang/AST/TypeLoc.h47
-rw-r--r--include/clang/AST/TypeNodes.def1
-rw-r--r--include/clang/Basic/BuiltinsARM.def14
-rw-r--r--include/clang/Basic/BuiltinsX86.def1
-rw-r--r--include/clang/Basic/DeclNodes.td1
-rw-r--r--include/clang/Basic/Diagnostic.h9
-rw-r--r--include/clang/Basic/DiagnosticCommonKinds.td6
-rw-r--r--include/clang/Basic/DiagnosticFrontendKinds.td3
-rw-r--r--include/clang/Basic/DiagnosticGroups.td8
-rw-r--r--include/clang/Basic/DiagnosticIDs.h21
-rw-r--r--include/clang/Basic/DiagnosticParseKinds.td22
-rw-r--r--include/clang/Basic/DiagnosticSemaKinds.td263
-rw-r--r--include/clang/Basic/ExceptionSpecificationType.h13
-rw-r--r--include/clang/Basic/IdentifierTable.h3
-rw-r--r--include/clang/Basic/LangOptions.h3
-rw-r--r--include/clang/Basic/SourceLocation.h3
-rw-r--r--include/clang/Basic/SourceManager.h8
-rw-r--r--include/clang/Basic/Specifiers.h1
-rw-r--r--include/clang/Basic/StmtNodes.td2
-rw-r--r--include/clang/Basic/TargetInfo.h9
-rw-r--r--include/clang/Basic/TokenKinds.def7
-rw-r--r--include/clang/Basic/TypeTraits.h3
-rw-r--r--include/clang/Basic/arm_neon.td7
-rw-r--r--include/clang/Driver/CC1AsOptions.td3
-rw-r--r--include/clang/Driver/CC1Options.td13
-rw-r--r--include/clang/Driver/Options.td17
-rw-r--r--include/clang/Driver/ToolChain.h2
-rw-r--r--include/clang/Frontend/ASTUnit.h26
-rw-r--r--include/clang/Frontend/CodeGenOptions.h4
-rw-r--r--include/clang/Frontend/DiagnosticOptions.h5
-rw-r--r--include/clang/Frontend/LangStandard.h20
-rw-r--r--include/clang/Frontend/LangStandards.def11
-rw-r--r--include/clang/Frontend/PreprocessorOptions.h5
-rw-r--r--include/clang/Frontend/Utils.h3
-rw-r--r--include/clang/Lex/HeaderSearch.h46
-rw-r--r--include/clang/Lex/LiteralSupport.h8
-rw-r--r--include/clang/Lex/PreprocessingRecord.h11
-rw-r--r--include/clang/Lex/Preprocessor.h3
-rw-r--r--include/clang/Parse/Parser.h60
-rw-r--r--include/clang/Sema/CodeCompleteConsumer.h5
-rw-r--r--include/clang/Sema/DeclSpec.h45
-rw-r--r--include/clang/Sema/Initialization.h49
-rw-r--r--include/clang/Sema/Lookup.h16
-rw-r--r--include/clang/Sema/Overload.h3
-rw-r--r--include/clang/Sema/Scope.h7
-rw-r--r--include/clang/Sema/Sema.h326
-rw-r--r--include/clang/Sema/Template.h3
-rw-r--r--include/clang/Serialization/ASTBitCodes.h37
-rw-r--r--include/clang/Serialization/ASTReader.h24
-rw-r--r--include/clang/Serialization/ASTWriter.h23
-rw-r--r--include/clang/StaticAnalyzer/Core/Checker.h22
-rw-r--r--include/clang/StaticAnalyzer/Core/CheckerManager.h35
-rw-r--r--include/clang/StaticAnalyzer/Core/PathSensitive/BasicValueFactory.h9
-rw-r--r--include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h16
-rw-r--r--include/clang/StaticAnalyzer/Core/PathSensitive/GRState.h6
-rw-r--r--include/clang/StaticAnalyzer/Core/PathSensitive/ObjCMessage.h1
-rw-r--r--include/clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h2
-rw-r--r--include/clang/StaticAnalyzer/Core/PathSensitive/Store.h2
-rw-r--r--include/clang/StaticAnalyzer/Core/PathSensitive/SubEngine.h17
-rw-r--r--include/clang/Tooling/Tooling.h81
-rw-r--r--lib/AST/APValue.cpp8
-rw-r--r--lib/AST/ASTContext.cpp351
-rw-r--r--lib/AST/ASTDiagnostic.cpp8
-rw-r--r--lib/AST/ASTImporter.cpp29
-rw-r--r--lib/AST/Decl.cpp78
-rw-r--r--lib/AST/DeclBase.cpp9
-rw-r--r--lib/AST/DeclCXX.cpp323
-rw-r--r--lib/AST/DeclObjC.cpp3
-rw-r--r--lib/AST/DeclPrinter.cpp126
-rw-r--r--lib/AST/DeclTemplate.cpp31
-rw-r--r--lib/AST/DumpXML.cpp10
-rw-r--r--lib/AST/Expr.cpp75
-rw-r--r--lib/AST/ExprClassification.cpp11
-rw-r--r--lib/AST/ExprConstant.cpp616
-rw-r--r--lib/AST/ExternalASTSource.cpp2
-rw-r--r--lib/AST/ItaniumMangle.cpp141
-rw-r--r--lib/AST/Mangle.cpp5
-rw-r--r--lib/AST/MicrosoftMangle.cpp4
-rw-r--r--lib/AST/RecordLayoutBuilder.cpp154
-rw-r--r--lib/AST/StmtPrinter.cpp10
-rw-r--r--lib/AST/StmtProfile.cpp4
-rw-r--r--lib/AST/Type.cpp116
-rw-r--r--lib/AST/TypePrinter.cpp17
-rw-r--r--lib/Analysis/AnalysisContext.cpp8
-rw-r--r--lib/Analysis/CFG.cpp69
-rw-r--r--lib/Analysis/CocoaConventions.cpp1
-rw-r--r--lib/Analysis/LiveVariables.cpp2
-rw-r--r--lib/Analysis/UninitializedValues.cpp51
-rw-r--r--lib/Basic/Diagnostic.cpp47
-rw-r--r--lib/Basic/DiagnosticIDs.cpp185
-rw-r--r--lib/Basic/FileManager.cpp4
-rw-r--r--lib/Basic/IdentifierTable.cpp1
-rw-r--r--lib/Basic/SourceManager.cpp73
-rw-r--r--lib/Basic/Targets.cpp46
-rw-r--r--lib/CMakeLists.txt1
-rw-r--r--lib/CodeGen/BackendUtil.cpp75
-rw-r--r--lib/CodeGen/CGBlocks.cpp64
-rw-r--r--lib/CodeGen/CGBuiltin.cpp59
-rw-r--r--lib/CodeGen/CGCXX.cpp24
-rw-r--r--lib/CodeGen/CGCall.cpp120
-rw-r--r--lib/CodeGen/CGCall.h9
-rw-r--r--lib/CodeGen/CGClass.cpp262
-rw-r--r--lib/CodeGen/CGDebugInfo.cpp60
-rw-r--r--lib/CodeGen/CGDebugInfo.h2
-rw-r--r--lib/CodeGen/CGDecl.cpp19
-rw-r--r--lib/CodeGen/CGDeclCXX.cpp12
-rw-r--r--lib/CodeGen/CGException.cpp188
-rw-r--r--lib/CodeGen/CGExpr.cpp5
-rw-r--r--lib/CodeGen/CGExprAgg.cpp2
-rw-r--r--lib/CodeGen/CGExprCXX.cpp437
-rw-r--r--lib/CodeGen/CGExprConstant.cpp11
-rw-r--r--lib/CodeGen/CGExprScalar.cpp100
-rw-r--r--lib/CodeGen/CGObjC.cpp100
-rw-r--r--lib/CodeGen/CGObjCGNU.cpp99
-rw-r--r--lib/CodeGen/CGObjCMac.cpp755
-rw-r--r--lib/CodeGen/CGObjCRuntime.cpp13
-rw-r--r--lib/CodeGen/CGObjCRuntime.h7
-rw-r--r--lib/CodeGen/CGRecordLayoutBuilder.cpp8
-rw-r--r--lib/CodeGen/CGStmt.cpp12
-rw-r--r--lib/CodeGen/CGVTT.cpp2
-rw-r--r--lib/CodeGen/CGVTables.cpp183
-rw-r--r--lib/CodeGen/CodeGenFunction.cpp64
-rw-r--r--lib/CodeGen/CodeGenFunction.h25
-rw-r--r--lib/CodeGen/CodeGenModule.cpp189
-rw-r--r--lib/CodeGen/CodeGenModule.h10
-rw-r--r--lib/CodeGen/CodeGenTypes.h5
-rw-r--r--lib/CodeGen/ItaniumCXXABI.cpp14
-rw-r--r--lib/CodeGen/ModuleBuilder.cpp2
-rw-r--r--lib/CodeGen/TargetInfo.cpp90
-rw-r--r--lib/Driver/Driver.cpp31
-rw-r--r--lib/Driver/HostInfo.cpp15
-rw-r--r--lib/Driver/ToolChains.cpp205
-rw-r--r--lib/Driver/ToolChains.h5
-rw-r--r--lib/Driver/Tools.cpp242
-rw-r--r--lib/Driver/Tools.h14
-rw-r--r--lib/Frontend/ASTConsumers.cpp2
-rw-r--r--lib/Frontend/ASTUnit.cpp137
-rw-r--r--lib/Frontend/CMakeLists.txt1
-rw-r--r--lib/Frontend/CompilerInstance.cpp3
-rw-r--r--lib/Frontend/CompilerInvocation.cpp69
-rw-r--r--lib/Frontend/CreateInvocationFromCommandLine.cpp2
-rw-r--r--lib/Frontend/DiagChecker.cpp301
-rw-r--r--lib/Frontend/InitHeaderSearch.cpp52
-rw-r--r--lib/Frontend/InitPreprocessor.cpp69
-rw-r--r--lib/Frontend/LogDiagnosticPrinter.cpp4
-rw-r--r--lib/Frontend/TextDiagnosticPrinter.cpp36
-rw-r--r--lib/Frontend/Warnings.cpp51
-rw-r--r--lib/Headers/emmintrin.h14
-rw-r--r--lib/Headers/mmintrin.h8
-rw-r--r--lib/Headers/xmmintrin.h5
-rw-r--r--lib/Index/CallGraph.cpp2
-rw-r--r--lib/Index/Indexer.cpp2
-rw-r--r--lib/Lex/HeaderSearch.cpp18
-rw-r--r--lib/Lex/Lexer.cpp3
-rw-r--r--lib/Lex/LiteralSupport.cpp19
-rw-r--r--lib/Lex/MacroInfo.cpp1
-rw-r--r--lib/Lex/PPDirectives.cpp4
-rw-r--r--lib/Lex/PPMacroExpansion.cpp53
-rw-r--r--lib/Lex/Pragma.cpp23
-rw-r--r--lib/Lex/PreprocessingRecord.cpp8
-rw-r--r--lib/Lex/Preprocessor.cpp5
-rwxr-xr-xlib/Makefile2
-rw-r--r--lib/Parse/ParseCXXInlineMethods.cpp157
-rw-r--r--lib/Parse/ParseDecl.cpp60
-rw-r--r--lib/Parse/ParseDeclCXX.cpp487
-rw-r--r--lib/Parse/ParseExpr.cpp72
-rw-r--r--lib/Parse/ParseExprCXX.cpp72
-rw-r--r--lib/Parse/ParseObjc.cpp8
-rw-r--r--lib/Parse/ParsePragma.cpp1
-rw-r--r--lib/Parse/ParseStmt.cpp37
-rw-r--r--lib/Parse/ParseTemplate.cpp8
-rw-r--r--lib/Parse/ParseTentative.cpp6
-rw-r--r--lib/Parse/Parser.cpp155
-rw-r--r--lib/Rewrite/RewriteObjC.cpp15
-rw-r--r--lib/Sema/AnalysisBasedWarnings.cpp7
-rw-r--r--lib/Sema/DeclSpec.cpp1
-rw-r--r--lib/Sema/JumpDiagnostics.cpp50
-rw-r--r--lib/Sema/Sema.cpp154
-rw-r--r--lib/Sema/SemaAccess.cpp102
-rw-r--r--lib/Sema/SemaCXXCast.cpp75
-rw-r--r--lib/Sema/SemaCXXScopeSpec.cpp45
-rw-r--r--lib/Sema/SemaChecking.cpp96
-rw-r--r--lib/Sema/SemaCodeComplete.cpp162
-rw-r--r--lib/Sema/SemaDecl.cpp474
-rw-r--r--lib/Sema/SemaDeclCXX.cpp2004
-rw-r--r--lib/Sema/SemaDeclObjC.cpp287
-rw-r--r--lib/Sema/SemaExceptionSpec.cpp28
-rw-r--r--lib/Sema/SemaExpr.cpp719
-rw-r--r--lib/Sema/SemaExprCXX.cpp238
-rw-r--r--lib/Sema/SemaExprObjC.cpp119
-rw-r--r--lib/Sema/SemaInit.cpp103
-rw-r--r--lib/Sema/SemaLookup.cpp211
-rw-r--r--lib/Sema/SemaOverload.cpp235
-rw-r--r--lib/Sema/SemaStmt.cpp134
-rw-r--r--lib/Sema/SemaTemplate.cpp688
-rw-r--r--lib/Sema/SemaTemplateDeduction.cpp19
-rw-r--r--lib/Sema/SemaTemplateInstantiate.cpp81
-rw-r--r--lib/Sema/SemaTemplateInstantiateDecl.cpp162
-rw-r--r--lib/Sema/SemaTemplateVariadic.cpp3
-rw-r--r--lib/Sema/SemaType.cpp182
-rw-r--r--lib/Sema/TreeTransform.h139
-rw-r--r--lib/Serialization/ASTReader.cpp211
-rw-r--r--lib/Serialization/ASTReaderDecl.cpp40
-rw-r--r--lib/Serialization/ASTReaderStmt.cpp6
-rw-r--r--lib/Serialization/ASTWriter.cpp109
-rw-r--r--lib/Serialization/ASTWriterDecl.cpp399
-rw-r--r--lib/Serialization/ASTWriterStmt.cpp31
-rw-r--r--lib/StaticAnalyzer/Checkers/CStringChecker.cpp112
-rw-r--r--lib/StaticAnalyzer/Checkers/NSErrorChecker.cpp2
-rw-r--r--lib/StaticAnalyzer/Core/BasicStore.cpp18
-rw-r--r--lib/StaticAnalyzer/Core/BasicValueFactory.cpp3
-rw-r--r--lib/StaticAnalyzer/Core/CFRefCount.cpp251
-rw-r--r--lib/StaticAnalyzer/Core/CXXExprEngine.cpp4
-rw-r--r--lib/StaticAnalyzer/Core/CheckerManager.cpp17
-rw-r--r--lib/StaticAnalyzer/Core/Environment.cpp27
-rw-r--r--lib/StaticAnalyzer/Core/ExprEngine.cpp34
-rw-r--r--lib/StaticAnalyzer/Core/FlatStore.cpp4
-rw-r--r--lib/StaticAnalyzer/Core/GRState.cpp16
-rw-r--r--lib/StaticAnalyzer/Core/ObjCMessage.cpp7
-rw-r--r--lib/StaticAnalyzer/Core/RegionStore.cpp26
-rw-r--r--lib/StaticAnalyzer/Core/SimpleConstraintManager.cpp3
-rw-r--r--lib/StaticAnalyzer/Core/SimpleSValBuilder.cpp6
-rw-r--r--lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp13
-rw-r--r--lib/Tooling/CMakeLists.txt6
-rw-r--r--lib/Tooling/JsonCompileCommandLineDatabase.cpp214
-rw-r--r--lib/Tooling/JsonCompileCommandLineDatabase.h107
-rw-r--r--lib/Tooling/Makefile15
-rw-r--r--lib/Tooling/Tooling.cpp322
-rw-r--r--test/Analysis/CFNumber.c7
-rw-r--r--test/Analysis/bstring.c37
-rw-r--r--test/Analysis/misc-ps-cxx0x.cpp11
-rw-r--r--test/Analysis/misc-ps-region-store.cpp19
-rw-r--r--test/Analysis/misc-ps-region-store.m24
-rw-r--r--test/Analysis/misc-ps.c83
-rw-r--r--test/Analysis/misc-ps.m25
-rw-r--r--test/Analysis/plist-output-alternate.m9
-rw-r--r--test/Analysis/retain-release.m10
-rw-r--r--test/Analysis/retain-release.mm306
-rw-r--r--test/Analysis/string.c174
-rw-r--r--test/CMakeLists.txt24
-rw-r--r--test/CXX/basic/basic.lookup/basic.lookup.argdep/p4.cpp3
-rw-r--r--test/CXX/class.access/class.friend/p2-cxx03.cpp2
-rw-r--r--test/CXX/class.access/p4.cpp6
-rw-r--r--test/CXX/class/class.friend/p2.cpp4
-rw-r--r--test/CXX/class/class.mem/p1b.cpp2
-rw-r--r--test/CXX/class/class.mem/p5-0x.cpp9
-rw-r--r--test/CXX/dcl.dcl/basic.namespace/namespace.def/p7.cpp2
-rw-r--r--test/CXX/dcl.dcl/dcl.spec/dcl.stc/p1.cpp32
-rw-r--r--test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p4.cpp25
-rw-r--r--test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p5.cpp8
-rw-r--r--test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.type.elab/p2-0x.cpp19
-rw-r--r--test/CXX/dcl.dcl/dcl.spec/dcl.type/p3-0x.cpp9
-rw-r--r--test/CXX/dcl.decl/dcl.init/dcl.init.aggr/p1-0x.cpp63
-rw-r--r--test/CXX/dcl.decl/dcl.init/p14-0x.cpp44
-rw-r--r--test/CXX/dcl.decl/dcl.init/p6.cpp12
-rw-r--r--test/CXX/except/except.spec/p1.cpp13
-rw-r--r--test/CXX/except/except.spec/p14.cpp14
-rw-r--r--test/CXX/except/except.spec/p9-dynamic.cpp2
-rw-r--r--test/CXX/expr/expr.const/p2-0x.cpp25
-rw-r--r--test/CXX/expr/expr.post/expr.call/p7-0x.cpp17
-rw-r--r--test/CXX/expr/expr.prim/p12-0x.cpp12
-rw-r--r--test/CXX/expr/expr.prim/p4-0x.cpp10
-rw-r--r--test/CXX/expr/expr.unary/expr.unary.noexcept/sema.cpp13
-rw-r--r--test/CXX/special/class.ctor/p5-0x.cpp173
-rw-r--r--test/CXX/special/class.dtor/p3-0x.cpp177
-rw-r--r--test/CXX/special/class.init/class.base.init/p8-0x.cpp23
-rw-r--r--test/CXX/special/class.init/class.base.init/p9-0x.cpp36
-rw-r--r--test/CXX/stmt.stmt/stmt.dcl/p3-0x.cpp55
-rw-r--r--test/CXX/stmt.stmt/stmt.dcl/p3.cpp47
-rw-r--r--test/CXX/stmt.stmt/stmt.iter/stmt.ranged/p1.cpp6
-rw-r--r--test/CXX/temp/temp.decls/p3.cpp7
-rw-r--r--test/CXX/temp/temp.decls/temp.alias/p1.cpp8
-rw-r--r--test/CXX/temp/temp.decls/temp.alias/p2.cpp45
-rw-r--r--test/CXX/temp/temp.decls/temp.alias/p3.cpp13
-rw-r--r--test/CXX/temp/temp.decls/temp.friend/p3.cpp2
-rw-r--r--test/CXX/temp/temp.decls/temp.variadic/ext-blocks.cpp7
-rw-r--r--test/CXX/temp/temp.fct.spec/temp.deduct/cwg1170.cpp41
-rw-r--r--test/CXX/temp/temp.param/p10-0x.cpp13
-rw-r--r--test/CXX/temp/temp.param/p11-0x.cpp31
-rw-r--r--test/CXX/temp/temp.param/p9-0x.cpp9
-rw-r--r--test/CXX/temp/temp.res/temp.dep/temp.dep.type/p1.cpp30
-rw-r--r--test/CXX/temp/temp.spec/temp.expl.spec/examples.cpp209
-rw-r--r--test/CXX/temp/temp.spec/temp.expl.spec/p15.cpp11
-rw-r--r--test/CXX/temp/temp.spec/temp.expl.spec/p16.cpp14
-rw-r--r--test/CXX/temp/temp.spec/temp.expl.spec/p17.cpp5
-rw-r--r--test/CXX/temp/temp.spec/temp.expl.spec/p5-example.cpp34
-rw-r--r--test/CXX/temp/temp.spec/temp.explicit/p2.cpp4
-rw-r--r--test/CXX/temp/temp.type/p1-0x.cpp23
-rw-r--r--test/CodeGen/2009-10-20-GlobalDebug.c1
-rw-r--r--test/CodeGen/altivec.c2
-rw-r--r--test/CodeGen/arm-asm.c7
-rw-r--r--test/CodeGen/asm-errors.c1
-rw-r--r--test/CodeGen/asm-label.c12
-rw-r--r--test/CodeGen/available-externally-suppress.c10
-rw-r--r--test/CodeGen/avx-cmp-builtins.c46
-rw-r--r--test/CodeGen/builtins-ppc-altivec.c86
-rw-r--r--test/CodeGen/builtins-x86.c1
-rw-r--r--test/CodeGen/builtinshufflevector.c3
-rw-r--r--test/CodeGen/byval-memcpy-elim.c20
-rw-r--r--test/CodeGen/debug-info-crash.c1
-rw-r--r--test/CodeGen/debug-info.c9
-rw-r--r--test/CodeGen/decl.c4
-rw-r--r--test/CodeGen/ext-vector.c26
-rw-r--r--test/CodeGen/extern-inline.c1
-rw-r--r--test/CodeGen/frame-pointer-elim.c2
-rw-r--r--test/CodeGen/inline.c2
-rw-r--r--test/CodeGen/mmx-builtins.c1
-rw-r--r--test/CodeGen/ms_struct-bitfield-1.c91
-rw-r--r--test/CodeGen/ms_struct-bitfield-2.c135
-rw-r--r--test/CodeGen/ms_struct-bitfield-3.c49
-rw-r--r--test/CodeGen/ms_struct-pack.c125
-rw-r--r--test/CodeGen/ms_struct.c23
-rw-r--r--test/CodeGen/packed-arrays.c14
-rw-r--r--test/CodeGen/packed-structure.c9
-rw-r--r--test/CodeGen/palignr.c1
-rw-r--r--test/CodeGen/string-literal-short-wstring.c2
-rw-r--r--test/CodeGen/string-literal.c8
-rw-r--r--test/CodeGen/struct-passing.c4
-rw-r--r--test/CodeGen/transparent-union.c2
-rw-r--r--test/CodeGen/x86_32-arguments-darwin.c6
-rw-r--r--test/CodeGen/x86_32-arguments-linux.c4
-rw-r--r--test/CodeGen/x86_64-arguments.c2
-rw-r--r--test/CodeGenCXX/PR5050-constructor-conversion.cpp1
-rw-r--r--test/CodeGenCXX/abstract-class-ctors-dtors.cpp16
-rw-r--r--test/CodeGenCXX/arm.cpp8
-rw-r--r--test/CodeGenCXX/array-construction.cpp1
-rw-r--r--test/CodeGenCXX/array-operator-delete-call.cpp1
-rw-r--r--test/CodeGenCXX/call-arg-zero-temp.cpp1
-rw-r--r--test/CodeGenCXX/cast-conversion.cpp1
-rw-r--r--test/CodeGenCXX/constructor-conversion.cpp1
-rw-r--r--test/CodeGenCXX/constructor-default-arg.cpp1
-rw-r--r--test/CodeGenCXX/constructor-for-array-members.cpp1
-rw-r--r--test/CodeGenCXX/constructor-template.cpp1
-rw-r--r--test/CodeGenCXX/convert-to-fptr.cpp1
-rw-r--r--test/CodeGenCXX/copy-assign-synthesis-1.cpp1
-rw-r--r--test/CodeGenCXX/cxx0x-defaulted-templates.cpp19
-rw-r--r--test/CodeGenCXX/cxx0x-delegating-ctors.cpp42
-rw-r--r--test/CodeGenCXX/debug-info-pubtypes.cpp15
-rw-r--r--test/CodeGenCXX/decl-ref-init.cpp1
-rw-r--r--test/CodeGenCXX/default-constructor-for-members.cpp1
-rw-r--r--test/CodeGenCXX/derived-to-base-conv.cpp1
-rw-r--r--test/CodeGenCXX/destructors.cpp4
-rw-r--r--test/CodeGenCXX/eh.cpp22
-rw-r--r--test/CodeGenCXX/exceptions.cpp2
-rw-r--r--test/CodeGenCXX/global-array-destruction.cpp1
-rw-r--r--test/CodeGenCXX/global-llvm-constant.cpp22
-rw-r--r--test/CodeGenCXX/goto.cpp1
-rw-r--r--test/CodeGenCXX/instrument-functions.cpp30
-rw-r--r--test/CodeGenCXX/internal-linkage.cpp8
-rw-r--r--test/CodeGenCXX/mangle-alias-template.cpp41
-rw-r--r--test/CodeGenCXX/mangle-exprs.cpp16
-rw-r--r--test/CodeGenCXX/mangle-subst-std.cpp1
-rw-r--r--test/CodeGenCXX/mangle-unnameable-conversions.cpp14
-rw-r--r--test/CodeGenCXX/mangle.cpp43
-rw-r--r--test/CodeGenCXX/member-init-ctor.cpp14
-rw-r--r--test/CodeGenCXX/new.cpp52
-rw-r--r--test/CodeGenCXX/nrvo.cpp2
-rw-r--r--test/CodeGenCXX/pr9965.cpp12
-rw-r--r--test/CodeGenCXX/ptr-to-member-function.cpp1
-rw-r--r--test/CodeGenCXX/scoped-enums.cpp9
-rw-r--r--test/CodeGenCXX/skip-vtable-pointer-initialization.cpp200
-rw-r--r--test/CodeGenCXX/static-init-2.cpp2
-rw-r--r--test/CodeGenCXX/template-instantiation.cpp30
-rw-r--r--test/CodeGenCXX/threadsafe-statics-exceptions.cpp2
-rw-r--r--test/CodeGenCXX/thunks.cpp30
-rw-r--r--test/CodeGenCXX/vararg-non-pod.cpp16
-rw-r--r--test/CodeGenCXX/virtual-base-destructor-call.cpp10
-rw-r--r--test/CodeGenCXX/x86_32-arguments.cpp4
-rw-r--r--test/CodeGenObjC/bitfield-ivar-offsets.m14
-rw-r--r--test/CodeGenObjC/blocks-2.m2
-rw-r--r--test/CodeGenObjC/constant-string-class-1.m23
-rw-r--r--test/CodeGenObjC/constant-string-class.m2
-rw-r--r--test/CodeGenObjC/debug-info-block-helper.m30
-rw-r--r--test/CodeGenObjC/debug-info-blocks.m55
-rw-r--r--test/CodeGenObjC/debug-info-class-extension.m15
-rw-r--r--test/CodeGenObjC/debug-info-class-extension2.m14
-rw-r--r--test/CodeGenObjC/debug-info-class-extension3.m12
-rw-r--r--test/CodeGenObjC/debug-info-crash.m1
-rw-r--r--test/CodeGenObjC/debug-info-getter-name.m3
-rw-r--r--test/CodeGenObjC/debug-info-pubtypes.m19
-rw-r--r--test/CodeGenObjC/debug-info-static-var.m1
-rw-r--r--test/CodeGenObjC/debug-property-synth.m19
-rw-r--r--test/CodeGenObjC/encode-test.m17
-rw-r--r--test/CodeGenObjC/forward-decl-param.m19
-rw-r--r--test/CodeGenObjC/instance-method-metadata.m1
-rw-r--r--test/CodeGenObjC/interface-layout-64.m22
-rw-r--r--test/CodeGenObjC/ivar-layout-array0-struct.m1
-rw-r--r--test/CodeGenObjC/ivar-layout-no-optimize.m1
-rw-r--r--test/CodeGenObjC/messages-2.m28
-rw-r--r--test/CodeGenObjC/metadata-symbols-64.m2
-rw-r--r--test/CodeGenObjC/no-vararg-messaging.m1
-rw-r--r--test/CodeGenObjC/objc-read-weak-byref.m1
-rw-r--r--test/CodeGenObjC/protocol-in-extended-class.m1
-rw-r--r--test/CodeGenObjC/try.m1
-rw-r--r--test/CodeGenObjC/unwind-fn.m14
-rw-r--r--test/CodeGenObjCXX/block-in-template-inst.mm71
-rw-r--r--test/CodeGenObjCXX/blocks.mm18
-rw-r--r--test/CodeGenObjCXX/encode.mm70
-rw-r--r--test/CodeGenObjCXX/mangle.mm12
-rw-r--r--test/CodeGenObjCXX/property-object-conditional-exp.mm7
-rw-r--r--test/Driver/cc-log-diagnostics.c12
-rw-r--r--test/Driver/cfi.c8
-rw-r--r--test/Driver/darwin-debug-flags.c2
-rw-r--r--test/Driver/darwin-ld.c7
-rw-r--r--test/Driver/nostdlib.c4
-rw-r--r--test/Driver/rewrite-objc.m2
-rw-r--r--test/Driver/sysroot.c18
-rw-r--r--test/FixIt/fixit-cxx0x.cpp2
-rw-r--r--test/Frontend/diagnostic-name.c4
-rw-r--r--test/Frontend/ir-support-codegen.ll1
-rw-r--r--test/Frontend/undef.c4
-rw-r--r--test/Index/Inputs/guarded.h6
-rw-r--r--test/Index/Inputs/pragma-once.h3
-rw-r--r--test/Index/annotate-context-sensitive.cpp12
-rw-r--r--test/Index/annotate-tokens-pp.c8
-rw-r--r--test/Index/annotate-tokens.m8
-rw-r--r--test/Index/complete-kvc.m20
-rw-r--r--test/Index/complete-member-access.m17
-rw-r--r--test/Index/complete-property-flags.m1
-rw-r--r--test/Index/nested-macro-instantiations.cpp20
-rw-r--r--test/Index/overrides.cpp4
-rw-r--r--test/Index/properties-class-extensions.m2
-rw-r--r--test/Index/recursive-cxx-member-calls.cpp34
-rw-r--r--test/Index/usrs.cpp22
-rw-r--r--test/Index/usrs.m2
-rw-r--r--test/Lexer/block_cmt_end.c8
-rw-r--r--test/Lexer/has_extension.c30
-rw-r--r--test/Lexer/has_extension_cxx.cpp36
-rw-r--r--test/Lexer/has_feature_c1x.c20
-rw-r--r--test/Lexer/has_feature_cxx0x.cpp11
-rw-r--r--test/Lexer/has_feature_type_traits.cpp10
-rw-r--r--test/Misc/Inputs/include.h2
-rw-r--r--test/Misc/diag-format.c34
-rw-r--r--test/Misc/include-stack-for-note-flag.cpp10
-rw-r--r--test/PCH/cxx-alias-decl.cpp20
-rw-r--r--test/PCH/cxx-alias-decl.h11
-rw-r--r--test/PCH/cxx-for-range.cpp6
-rw-r--r--test/PCH/cxx-member-init.cpp22
-rw-r--r--test/PCH/cxx-reference.cpp6
-rw-r--r--test/PCH/cxx-static_assert.cpp15
-rw-r--r--test/PCH/cxx-static_assert.h9
-rw-r--r--test/PCH/cxx0x-default-delete.cpp23
-rw-r--r--test/PCH/cxx0x-delegating-ctors.cpp20
-rw-r--r--test/PCH/modified-header-error.c11
-rw-r--r--test/PCH/objc_methods.h2
-rw-r--r--test/PCH/objc_methods.m2
-rw-r--r--test/PCH/objcxx-ivar-class.mm2
-rw-r--r--test/Parser/MicrosoftExtensions.cpp100
-rw-r--r--test/Parser/cxx-default-delete.cpp15
-rw-r--r--test/Parser/cxx-ext-delete-default.cpp11
-rw-r--r--test/Parser/cxx-friend.cpp6
-rw-r--r--test/Parser/cxx0x-member-initializers.cpp15
-rw-r--r--test/Parser/nested-namespaces-recovery.cpp24
-rw-r--r--test/Parser/opencl-astype.cl20
-rw-r--r--test/Preprocessor/if_warning.c4
-rw-r--r--test/Preprocessor/pragma_sysheader.c9
-rw-r--r--test/Sema/MicrosoftExtensions.c8
-rw-r--r--test/Sema/arm-neon-types.c9
-rw-r--r--test/Sema/asm.c8
-rw-r--r--test/Sema/attr-unknown.c2
-rw-r--r--test/Sema/builtins-arm.c5
-rw-r--r--test/Sema/carbon.c2
-rw-r--r--test/Sema/exprs.c18
-rw-r--r--test/Sema/illegal-types.c2
-rw-r--r--test/Sema/parentheses.c24
-rw-r--r--test/Sema/parentheses.cpp31
-rw-r--r--test/Sema/stdcall-fastcall.c3
-rw-r--r--test/Sema/uninit-variables.c13
-rw-r--r--test/Sema/x86-builtin-palignr.c3
-rw-r--r--test/SemaCXX/MicrosoftExtensions.cpp74
-rw-r--r--test/SemaCXX/PR9572.cpp8
-rw-r--r--test/SemaCXX/PR9884.cpp17
-rw-r--r--test/SemaCXX/PR9902.cpp28
-rw-r--r--test/SemaCXX/PR9908.cpp32
-rw-r--r--test/SemaCXX/aggregate-initialization.cpp4
-rw-r--r--test/SemaCXX/alias-template.cpp147
-rw-r--r--test/SemaCXX/anonymous-union.cpp30
-rw-r--r--test/SemaCXX/attr-cxx0x.cpp5
-rw-r--r--test/SemaCXX/attr-noreturn.cpp17
-rw-r--r--test/SemaCXX/attr-regparm.cpp3
-rw-r--r--test/SemaCXX/class.cpp2
-rw-r--r--test/SemaCXX/conversion.cpp11
-rw-r--r--test/SemaCXX/copy-constructor-error.cpp4
-rw-r--r--test/SemaCXX/cxx0x-cursory-default-delete.cpp69
-rw-r--r--test/SemaCXX/cxx0x-defaulted-functions.cpp45
-rw-r--r--test/SemaCXX/cxx0x-delegating-ctors.cpp24
-rw-r--r--test/SemaCXX/cxx0x-deleted-default-ctor.cpp120
-rw-r--r--test/SemaCXX/cxx0x-nontrivial-union.cpp22
-rw-r--r--test/SemaCXX/default-arg-special-member.cpp12
-rw-r--r--test/SemaCXX/default-constructor-initializers.cpp7
-rw-r--r--test/SemaCXX/defaulted-ctor-loop.cpp14
-rw-r--r--test/SemaCXX/deleted-function-extension.cpp8
-rw-r--r--test/SemaCXX/deleted-function.cpp5
-rw-r--r--test/SemaCXX/dependent-noexcept-unevaluated.cpp41
-rw-r--r--test/SemaCXX/dependent-types.cpp5
-rw-r--r--test/SemaCXX/destructor.cpp175
-rw-r--r--test/SemaCXX/enum-scoped.cpp10
-rw-r--r--test/SemaCXX/expressions.cpp31
-rw-r--r--test/SemaCXX/generalized-initializers.cpp174
-rw-r--r--test/SemaCXX/implicit-exception-spec.cpp63
-rw-r--r--test/SemaCXX/implicit-member-functions.cpp2
-rw-r--r--test/SemaCXX/member-expr.cpp12
-rw-r--r--test/SemaCXX/member-init.cpp50
-rw-r--r--test/SemaCXX/member-pointer.cpp25
-rw-r--r--test/SemaCXX/nullptr.cpp57
-rw-r--r--test/SemaCXX/overload-call.cpp22
-rw-r--r--test/SemaCXX/overloaded-operator.cpp17
-rw-r--r--test/SemaCXX/redeclared-alias-template.cpp23
-rw-r--r--test/SemaCXX/reinterpret-cast.cpp162
-rw-r--r--test/SemaCXX/return.cpp16
-rw-r--r--test/SemaCXX/struct-class-redecl.cpp160
-rw-r--r--test/SemaCXX/switch.cpp2
-rw-r--r--test/SemaCXX/tag-ambig.cpp28
-rw-r--r--test/SemaCXX/type-traits.cpp102
-rw-r--r--test/SemaCXX/underlying_type.cpp37
-rw-r--r--test/SemaCXX/value-initialization.cpp9
-rw-r--r--test/SemaCXX/vararg-non-pod.cpp9
-rw-r--r--test/SemaCXX/vtable-instantiation.cc50
-rw-r--r--test/SemaCXX/warn-bad-memaccess.cpp70
-rw-r--r--test/SemaCXX/warn-non-pod-memset.cpp63
-rw-r--r--test/SemaCXX/warn-pure-virtual-call-from-ctor-dtor.cpp7
-rw-r--r--test/SemaObjC/exprs.m10
-rw-r--r--test/SemaObjC/gc-attributes.m22
-rw-r--r--test/SemaObjC/objc2-warn-weak-decl.m2
-rw-r--r--test/SemaObjC/related-result-type-inference.m171
-rw-r--r--test/SemaObjCXX/blocks.mm26
-rw-r--r--test/SemaObjCXX/gc-attributes.mm22
-rw-r--r--test/SemaObjCXX/namespace-lookup.mm14
-rw-r--r--test/SemaObjCXX/nullptr.mm13
-rw-r--r--test/SemaObjCXX/overload-gc.mm4
-rw-r--r--test/SemaObjCXX/overload.mm4
-rw-r--r--test/SemaObjCXX/related-result-type-inference.mm71
-rw-r--r--test/SemaTemplate/alias-church-numerals.cpp34
-rw-r--r--test/SemaTemplate/alias-nested-nontag.cpp6
-rw-r--r--test/SemaTemplate/alias-template-template-param.cpp7
-rw-r--r--test/SemaTemplate/alias-templates.cpp70
-rw-r--r--test/SemaTemplate/deduction-crash.cpp36
-rw-r--r--test/SemaTemplate/dependent-names-no-std.cpp21
-rw-r--r--test/SemaTemplate/dependent-names.cpp135
-rw-r--r--test/SemaTemplate/friend-template.cpp8
-rw-r--r--test/SemaTemplate/instantiate-call.cpp5
-rw-r--r--test/SemaTemplate/instantiate-function-1.cpp22
-rw-r--r--test/SemaTemplate/instantiate-init.cpp52
-rw-r--r--test/SemaTemplate/partial-spec-instantiate.cpp10
-rw-r--r--test/SemaTemplate/rdar9173693.cpp6
-rw-r--r--test/SemaTemplate/typename-specifier.cpp31
-rw-r--r--test/lit.cfg30
-rw-r--r--tools/c-index-test/c-index-test.c54
-rw-r--r--tools/driver/cc1as_main.cpp2
-rw-r--r--tools/libclang/CIndex.cpp114
-rw-r--r--tools/libclang/CIndexCodeCompletion.cpp3
-rw-r--r--tools/libclang/CIndexDiagnostic.cpp3
-rw-r--r--tools/libclang/CIndexUSRs.cpp3
-rw-r--r--tools/libclang/CIndexer.h3
-rw-r--r--tools/libclang/CXCursor.cpp1
-rw-r--r--tools/libclang/CXType.cpp7
-rw-r--r--tools/libclang/libclang.darwin.exports2
-rw-r--r--tools/libclang/libclang.exports2
-rw-r--r--unittests/CMakeLists.txt12
-rw-r--r--unittests/Tooling/JsonCompileCommandLineDatabaseTest.cpp232
-rw-r--r--unittests/Tooling/ToolingTest.cpp175
-rw-r--r--www/CheckerNotes.html9
-rw-r--r--www/StaticAnalysis.html21
-rw-r--r--www/StaticAnalysisUsage.html21
-rw-r--r--www/analyzer/latest_checker.html.incl2
-rw-r--r--www/analyzer/release_notes.html15
-rw-r--r--www/clang-tutorial.html56
-rw-r--r--www/comparison.html17
-rw-r--r--www/compatibility.html24
-rw-r--r--www/cxx_status.html15
-rw-r--r--www/diagnostics.html122
-rw-r--r--www/distclang_status.html30
-rw-r--r--www/features.html1
-rw-r--r--www/libstdc++4.4-clang0x.patch239
603 files changed, 21539 insertions, 8388 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 7b54dea..aa89823 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -57,6 +57,13 @@ set(CLANG_RESOURCE_DIR "" CACHE STRING
set(C_INCLUDE_DIRS "" CACHE STRING
"Colon separated list of directories clang will search for headers.")
+set(CLANG_VENDOR "" CACHE STRING
+ "Vendor-specific text for showing with version information.")
+
+if( CLANG_VENDOR )
+ add_definitions( -DCLANG_VENDOR="${CLANG_VENDOR} " )
+endif()
+
set(CLANG_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR})
set(CLANG_BINARY_DIR ${CMAKE_CURRENT_BINARY_DIR})
@@ -103,7 +110,7 @@ configure_file(
${CMAKE_CURRENT_BINARY_DIR}/include/clang/Basic/Version.inc)
# Add appropriate flags for GCC
-if (CMAKE_COMPILER_IS_GNUCXX)
+if (LLVM_COMPILER_IS_GCC_COMPATIBLE)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fno-common -Woverloaded-virtual -Wcast-qual -fno-strict-aliasing -pedantic -Wno-long-long -Wall -W -Wno-unused-parameter -Wwrite-strings")
endif ()
diff --git a/clang.xcodeproj/project.pbxproj b/clang.xcodeproj/project.pbxproj
index e14448c..1612d12 100644
--- a/clang.xcodeproj/project.pbxproj
+++ b/clang.xcodeproj/project.pbxproj
@@ -6,6 +6,12 @@
objectVersion = 42;
objects = {
+/* Begin PBXBuildFile section */
+ BD6B0EDF13A1824C00B8E3FE /* Mangle.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BD6B0EDE13A1824C00B8E3FE /* Mangle.cpp */; };
+ BD6B0EE213A182A600B8E3FE /* ItaniumMangle.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BD6B0EE113A182A600B8E3FE /* ItaniumMangle.cpp */; };
+ BD6B0EE413A182DA00B8E3FE /* MicrosoftMangle.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BD6B0EE313A182DA00B8E3FE /* MicrosoftMangle.cpp */; };
+/* End PBXBuildFile section */
+
/* Begin PBXCopyFilesBuildPhase section */
8DD76F690486A84900D96B5E /* CopyFiles */ = {
isa = PBXCopyFilesBuildPhase;
@@ -472,6 +478,9 @@
BD59A952121496B9003A5A02 /* SemaConsumer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SemaConsumer.h; path = clang/Sema/SemaConsumer.h; sourceTree = "<group>"; };
BD59A953121496B9003A5A02 /* SemaDiagnostic.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SemaDiagnostic.h; path = clang/Sema/SemaDiagnostic.h; sourceTree = "<group>"; };
BD59A954121496B9003A5A02 /* Template.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Template.h; path = clang/Sema/Template.h; sourceTree = "<group>"; };
+ BD6B0EDE13A1824C00B8E3FE /* Mangle.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Mangle.cpp; sourceTree = "<group>"; };
+ BD6B0EE113A182A600B8E3FE /* ItaniumMangle.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ItaniumMangle.cpp; sourceTree = "<group>"; };
+ BD6B0EE313A182DA00B8E3FE /* MicrosoftMangle.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = MicrosoftMangle.cpp; sourceTree = "<group>"; };
BDF87CF60FD746F300BBF872 /* SemaTemplateDeduction.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = SemaTemplateDeduction.cpp; path = lib/Sema/SemaTemplateDeduction.cpp; sourceTree = "<group>"; tabWidth = 2; };
BF89C3E111595818001C2D68 /* AnalysisBasedWarnings.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = AnalysisBasedWarnings.cpp; path = lib/Sema/AnalysisBasedWarnings.cpp; sourceTree = "<group>"; };
BF89C3E5115958A1001C2D68 /* TargetAttributesSema.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = TargetAttributesSema.h; path = lib/Sema/TargetAttributesSema.h; sourceTree = "<group>"; };
@@ -1514,6 +1523,9 @@
DEC8D9920A9433F400353FCA /* AST */ = {
isa = PBXGroup;
children = (
+ BD6B0EDE13A1824C00B8E3FE /* Mangle.cpp */,
+ BD6B0EE313A182DA00B8E3FE /* MicrosoftMangle.cpp */,
+ BD6B0EE113A182A600B8E3FE /* ItaniumMangle.cpp */,
BF9FEE051225E770003A8B71 /* MicrosoftCXXABI.cpp */,
BF9FEE031225E759003A8B71 /* ItaniumCXXABI.cpp */,
BF9FEE011225E73F003A8B71 /* ExprClassification.cpp */,
@@ -1900,6 +1912,9 @@
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
+ BD6B0EDF13A1824C00B8E3FE /* Mangle.cpp in Sources */,
+ BD6B0EE213A182A600B8E3FE /* ItaniumMangle.cpp in Sources */,
+ BD6B0EE413A182DA00B8E3FE /* MicrosoftMangle.cpp in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
diff --git a/docs/LanguageExtensions.html b/docs/LanguageExtensions.html
index f86835a..8f43725 100644
--- a/docs/LanguageExtensions.html
+++ b/docs/LanguageExtensions.html
@@ -32,28 +32,42 @@ td {
</ul>
<li><a href="#checking_upcoming_features">Checks for Upcoming Standard Language Features</a></li>
<ul>
- <li><a href="#cxx_attributes">C++0x attributes</a></li>
- <li><a href="#cxx_decltype">C++0x <tt>decltype()</tt></a></li>
- <li><a href="#cxx_default_function_template_args">C++0x default template arguments in function templates</a></li>
- <li><a href="#cxx_deleted_functions">C++0x deleted functions</a></li>
- <li><a href="#cxx_lambdas">C++0x lambdas</a></li>
- <li><a href="#cxx_nullptr">C++0x nullptr</a></li>
- <li><a href="#cxx_override_control">C++0x override control</a></li>
- <li><a href="#cxx_range_for">C++0x range-based for loop</a></li>
- <li><a href="#cxx_rvalue_references">C++0x rvalue references</a></li>
- <li><a href="#cxx_reference_qualified_functions">C++0x reference-qualified functions</a></li>
- <li><a href="#cxx_static_assert">C++0x <tt>static_assert()</tt></a></li>
- <li><a href="#cxx_auto_type">C++0x type inference</a></li>
- <li><a href="#cxx_variadic_templates">C++0x variadic templates</a></li>
- <li><a href="#cxx_inline_namespaces">C++0x inline namespaces</a></li>
- <li><a href="#cxx_strong_enums">C++0x strongly-typed enumerations</a></li>
- <li><a href="#cxx_trailing_return">C++0x trailing return type</a></li>
- <li><a href="#cxx_noexcept">C++0x noexcept specification</a></li>
+ <li><a href="#cxx0x">C++0x</a>
+ <ul>
+ <li><a href="#cxx_decltype">C++0x <tt>decltype()</tt></a></li>
+ <li><a href="#cxx_access_control_sfinae">C++0x SFINAE includes access control</a></li>
+ <li><a href="#cxx_alias_templates">C++0x alias templates</a></li>
+ <li><a href="#cxx_attributes">C++0x attributes</a></li>
+ <li><a href="#cxx_default_function_template_args">C++0x default template arguments in function templates</a></li>
+ <li><a href="#cxx_deleted_functions">C++0x deleted functions</a></li>
+ <li><a href="#cxx_lambdas">C++0x lambdas</a></li>
+ <li><a href="#cxx_nullptr">C++0x nullptr</a></li>
+ <li><a href="#cxx_override_control">C++0x override control</a></li>
+ <li><a href="#cxx_range_for">C++0x range-based for loop</a></li>
+ <li><a href="#cxx_rvalue_references">C++0x rvalue references</a></li>
+ <li><a href="#cxx_reference_qualified_functions">C++0x reference-qualified functions</a></li>
+ <li><a href="#cxx_static_assert">C++0x <tt>static_assert()</tt></a></li>
+ <li><a href="#cxx_auto_type">C++0x type inference</a></li>
+ <li><a href="#cxx_variadic_templates">C++0x variadic templates</a></li>
+ <li><a href="#cxx_inline_namespaces">C++0x inline namespaces</a></li>
+ <li><a href="#cxx_strong_enums">C++0x strongly-typed enumerations</a></li>
+ <li><a href="#cxx_trailing_return">C++0x trailing return type</a></li>
+ <li><a href="#cxx_noexcept">C++0x noexcept specification</a></li>
+ </ul>
+ <li><a href="#c1x">C1X</a>
+ <ul>
+ <li><a href="#c_generic_selections">C1X generic selections</a></li>
+ <li><a href="#c_static_assert">C1X <tt>_Static_assert()</tt></a></li>
+ </ul>
</ul>
<li><a href="#checking_type_traits">Checks for Type Traits</a></li>
<li><a href="#blocks">Blocks</a></li>
+<li><a href="#objc_features">Objective-C Features</a>
+ <ul>
+ <li><a href="#objc_instancetype">Related result types</a></li>
+ </ul>
+</li>
<li><a href="#overloading-in-c">Function Overloading in C</a></li>
-<li><a href="#generic-selections">Generic Selections</a></li>
<li><a href="#builtins">Builtin Functions</a>
<ul>
<li><a href="#__builtin_shufflevector">__builtin_shufflevector</a></li>
@@ -115,28 +129,48 @@ not. It can be used like this:</p>
<!-- ======================================================================= -->
-<h3 id="__has_feature">__has_feature</h3>
+<h3 id="__has_feature_extension">__has_feature and __has_extension</h3>
<!-- ======================================================================= -->
-<p>This function-like macro takes a single identifier argument that is the name
-of a feature. It evaluates to 1 if the feature is supported or 0 if not. It
-can be used like this:</p>
+<p>These function-like macros take a single identifier argument that is the
+name of a feature. <code>__has_feature</code> evaluates to 1 if the feature
+is both supported by Clang and standardized in the current language standard
+or 0 if not (but see <a href="#has_feature_back_compat">below</a>), while
+<code>__has_extension</code> evaluates to 1 if the feature is supported by
+Clang in the current language (either as a language extension or a standard
+language feature) or 0 if not. They can be used like this:</p>
<blockquote>
<pre>
#ifndef __has_feature // Optional of course.
#define __has_feature(x) 0 // Compatibility with non-clang compilers.
#endif
+#ifndef __has_extension
+ #define __has_extension __has_feature // Compatibility with pre-3.0 compilers.
+#endif
...
-#if __has_feature(attribute_overloadable) || \
- __has_feature(blocks)
-...
+#if __has_feature(cxx_rvalue_references)
+// This code will only be compiled with the -std=c++0x and -std=gnu++0x
+// options, because rvalue references are only standardized in C++0x.
+#endif
+
+#if __has_extension(cxx_rvalue_references)
+// This code will be compiled with the -std=c++0x, -std=gnu++0x, -std=c++98
+// and -std=gnu++98 options, because rvalue references are supported as a
+// language extension in C++98.
#endif
-...
</pre>
</blockquote>
+<p id="has_feature_back_compat">For backwards compatibility reasons,
+<code>__has_feature</code> can also be used to test for support for
+non-standardized features, i.e. features not prefixed <code>c_</code>,
+<code>cxx_</code> or <code>objc_</code>.</p>
+
+<p>If the <code>-pedantic-errors</code> option is given,
+<code>__has_extension</code> is equivalent to <code>__has_feature</code>.</p>
+
<p>The feature tag is described along with the language feature below.</p>
<!-- ======================================================================= -->
@@ -293,7 +327,7 @@ float4 foo(float2 a, float2 b) {
</pre>
</blockquote>
-<p>Query for this feature with __has_feature(attribute_ext_vector_type).</p>
+<p>Query for this feature with __has_extension(attribute_ext_vector_type).</p>
<p>See also <a href="#__builtin_shufflevector">__builtin_shufflevector</a>.</p>
@@ -318,8 +352,8 @@ will be incorporated into the appropriate diagnostic:</p>
</blockquote>
<p>Query for this feature
-with <tt>__has_feature(attribute_deprecated_with_message)</tt>
-and <tt>__has_feature(attribute_unavailable_with_message)</tt>.</p>
+with <tt>__has_extension(attribute_deprecated_with_message)</tt>
+and <tt>__has_extension(attribute_unavailable_with_message)</tt>.</p>
<!-- ======================================================================= -->
<h2 id="attributes-on-enumerators">Attributes on Enumerators</h2>
@@ -342,7 +376,7 @@ initializer, like so:</p>
<p>Attributes on the <tt>enum</tt> declaration do not apply to
individual enumerators.</p>
-<p>Query for this feature with <tt>__has_feature(enumerator_attributes)</tt>.</p>
+<p>Query for this feature with <tt>__has_extension(enumerator_attributes)</tt>.</p>
<!-- ======================================================================= -->
<h2 id="checking_language_features">Checks for Standard Language Features</h2>
@@ -365,106 +399,165 @@ compiling code with <tt>-fno-rtti</tt> disables the use of RTTI.</p>
<h2 id="checking_upcoming_features">Checks for Upcoming Standard Language Features</h2>
<!-- ======================================================================= -->
-<p>The <tt>__has_feature</tt> macro can be used to query if certain upcoming
-standard language features are enabled. Those features are listed here.</p>
+<p>The <tt>__has_feature</tt> or <tt>__has_extension</tt> macros can be used
+to query if certain upcoming standard language features are enabled. Those
+features are listed here. Features that are not yet implemented will be
+noted.</p>
+
+<h3 id="cxx0x">C++0x</h3>
-<p>Currently, all features listed here are slated for inclusion in the upcoming
-C++0x standard. As a result, all the features that clang supports are enabled
-with the <tt>-std=c++0x</tt> option when compiling C++ code. Features that are
-not yet implemented will be noted.</p>
+<p>The features listed below are slated for inclusion in the upcoming
+C++0x standard. As a result, all these features are enabled
+with the <tt>-std=c++0x</tt> option when compiling C++ code.</p>
-<h3 id="cxx_decltype">C++0x <tt>decltype()</tt></h3>
+<h4 id="cxx_decltype">C++0x <tt>decltype()</tt></h3>
-<p>Use <tt>__has_feature(cxx_decltype)</tt> to determine if support for the
+<p>Use <tt>__has_feature(cxx_decltype)</tt> or
+<tt>__has_extension(cxx_decltype)</tt> to determine if support for the
<tt>decltype()</tt> specifier is enabled.</p>
-<h3 id="cxx_attributes">C++0x attributes</h3>
+<h4 id="cxx_access_control_sfinae">C++0x SFINAE includes access control</h3>
+
+<p>Use <tt>__has_feature(cxx_access_control_sfinae)</tt> or <tt>__has_extension(cxx_access_control_sfinae)</tt> to determine whether access-control errors (e.g., calling a private constructor) are considered to be template argument deduction errors (aka SFINAE errors), per <a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1170">C++ DR1170</a>.</p>
+
+<h4 id="cxx_alias_templates">C++0x alias templates</h3>
+
+<p>Use <tt>__has_feature(cxx_alias_templates)</tt> or
+<tt>__has_extension(cxx_alias_templates)</tt> to determine if support for
+C++0x's alias declarations and alias templates is enabled.</p>
+
+<h4 id="cxx_attributes">C++0x attributes</h3>
-<p>Use <tt>__has_feature(cxx_attributes)</tt> to determine if support for
-attribute parsing with C++0x's square bracket notation is enabled.</p>
+<p>Use <tt>__has_feature(cxx_attributes)</tt> or
+<tt>__has_extension(cxx_attributes)</tt> to determine if support for attribute
+parsing with C++0x's square bracket notation is enabled.</p>
-<h3 id="cxx_default_function_template_args">C++0x default template arguments in function templates</h3>
+<h4 id="cxx_default_function_template_args">C++0x default template arguments in function templates</h3>
-<p>Use <tt>__has_feature(cxx_default_function_template_args)</tt> to determine if support for default template arguments in function templates is enabled.</p>
+<p>Use <tt>__has_feature(cxx_default_function_template_args)</tt> or
+<tt>__has_extension(cxx_default_function_template_args)</tt> to determine
+if support for default template arguments in function templates is enabled.</p>
-<h3 id="cxx_deleted_functions">C++0x deleted functions</tt></h3>
+<h4 id="cxx_deleted_functions">C++0x deleted functions</tt></h3>
-<p>Use <tt>__has_feature(cxx_deleted_functions)</tt> to determine if support for
+<p>Use <tt>__has_feature(cxx_deleted_functions)</tt> or
+<tt>__has_extension(cxx_deleted_functions)</tt> to determine if support for
deleted function definitions (with <tt>= delete</tt>) is enabled.</p>
-<h3 id="cxx_lambdas">C++0x lambdas</h3>
+<h4 id="cxx_lambdas">C++0x lambdas</h3>
-<p>Use <tt>__has_feature(cxx_lambdas)</tt> to determine if support for
-lambdas is enabled. clang does not currently implement this feature.</p>
+<p>Use <tt>__has_feature(cxx_lambdas)</tt> or
+<tt>__has_extension(cxx_lambdas)</tt> to determine if support for lambdas
+is enabled. clang does not currently implement this feature.</p>
-<h3 id="cxx_nullptr">C++0x <tt>nullptr</tt></h3>
+<h4 id="cxx_nullptr">C++0x <tt>nullptr</tt></h3>
-<p>Use <tt>__has_feature(cxx_nullptr)</tt> to determine if support for
-<tt>nullptr</tt> is enabled. clang does not yet fully implement this
-feature.</p>
+<p>Use <tt>__has_feature(cxx_nullptr)</tt> or
+<tt>__has_extension(cxx_nullptr)</tt> to determine if support for
+<tt>nullptr</tt> is enabled.</p>
-<h3 id="cxx_override_control">C++0x <tt>override control</tt></h3>
+<h4 id="cxx_override_control">C++0x <tt>override control</tt></h3>
-<p>Use <tt>__has_feature(cxx_override_control)</tt> to determine if support for
+<p>Use <tt>__has_feature(cxx_override_control)</tt> or
+<tt>__has_extension(cxx_override_control)</tt> to determine if support for
the override control keywords is enabled.</p>
-<h3 id="cxx_reference_qualified_functions">C++0x reference-qualified functions</h3>
-<p>Use <tt>__has_feature(cxx_reference_qualified_functions)</tt> to determine if support for reference-qualified functions (e.g., member functions with <code>&amp;</code> or <code>&amp;&amp;</code> applied to <code>*this</code>) is enabled.</p>
+<h4 id="cxx_reference_qualified_functions">C++0x reference-qualified functions</h3>
+<p>Use <tt>__has_feature(cxx_reference_qualified_functions)</tt> or
+<tt>__has_extension(cxx_reference_qualified_functions)</tt> to determine
+if support for reference-qualified functions (e.g., member functions with
+<code>&amp;</code> or <code>&amp;&amp;</code> applied to <code>*this</code>)
+is enabled.</p>
-<h3 id="cxx_range_for">C++0x range-based for loop</tt></h3>
+<h4 id="cxx_range_for">C++0x range-based for loop</tt></h3>
-<p>Use <tt>__has_feature(cxx_range_for)</tt> to determine if support for
-the range-based for loop is enabled. </p>
+<p>Use <tt>__has_feature(cxx_range_for)</tt> or
+<tt>__has_extension(cxx_range_for)</tt> to determine if support for the
+range-based for loop is enabled. </p>
-<h3 id="cxx_rvalue_references">C++0x rvalue references</tt></h3>
+<h4 id="cxx_rvalue_references">C++0x rvalue references</tt></h3>
-<p>Use <tt>__has_feature(cxx_rvalue_references)</tt> to determine if support for
+<p>Use <tt>__has_feature(cxx_rvalue_references)</tt> or
+<tt>__has_extension(cxx_rvalue_references)</tt> to determine if support for
rvalue references is enabled. </p>
-<h3 id="cxx_static_assert">C++0x <tt>static_assert()</tt></h3>
+<h4 id="cxx_static_assert">C++0x <tt>static_assert()</tt></h3>
-<p>Use <tt>__has_feature(cxx_static_assert)</tt> to determine if support for
+<p>Use <tt>__has_feature(cxx_static_assert)</tt> or
+<tt>__has_extension(cxx_static_assert)</tt> to determine if support for
compile-time assertions using <tt>static_assert</tt> is enabled.</p>
-<h3 id="cxx_auto_type">C++0x type inference</h3>
+<h4 id="cxx_auto_type">C++0x type inference</h3>
-<p>Use <tt>__has_feature(cxx_auto_type)</tt> to determine C++0x type inference
-is supported using the <tt>auto</tt> specifier. If this is disabled,
-<tt>auto</tt> will instead be a storage class specifier, as in C or C++98.</p>
+<p>Use <tt>__has_feature(cxx_auto_type)</tt> or
+<tt>__has_extension(cxx_auto_type)</tt> to determine C++0x type inference is
+supported using the <tt>auto</tt> specifier. If this is disabled, <tt>auto</tt>
+will instead be a storage class specifier, as in C or C++98.</p>
-<h3 id="cxx_variadic_templates">C++0x variadic templates</h3>
+<h4 id="cxx_variadic_templates">C++0x variadic templates</h3>
-<p>Use <tt>__has_feature(cxx_variadic_templates)</tt> to determine if support
+<p>Use <tt>__has_feature(cxx_variadic_templates)</tt> or
+<tt>__has_extension(cxx_variadic_templates)</tt> to determine if support
for variadic templates is enabled.</p>
-<h3 id="cxx_inline_namespaces">C++0x inline namespaces</h3>
+<h4 id="cxx_inline_namespaces">C++0x inline namespaces</h3>
-<p>Use <tt>__has_feature(cxx_inline_namespaces)</tt> to determine if support for
+<p>Use <tt>__has_feature(cxx_inline_namespaces)</tt> or
+<tt>__has_extension(cxx_inline_namespaces)</tt> to determine if support for
inline namespaces is enabled.</p>
-<h3 id="cxx_trailing_return">C++0x trailing return type</h3>
+<h4 id="cxx_trailing_return">C++0x trailing return type</h3>
-<p>Use <tt>__has_feature(cxx_trailing_return)</tt> to determine if support for
-the alternate function declaration syntax with trailing return type is enabled.</p>
+<p>Use <tt>__has_feature(cxx_trailing_return)</tt> or
+<tt>__has_extension(cxx_trailing_return)</tt> to determine if support for the
+alternate function declaration syntax with trailing return type is enabled.</p>
-<h3 id="cxx_noexcept">C++0x noexcept</h3>
+<h4 id="cxx_noexcept">C++0x noexcept</h3>
-<p>Use <tt>__has_feature(cxx_noexcept)</tt> to determine if support for
-noexcept exception specifications is enabled.</p>
+<p>Use <tt>__has_feature(cxx_noexcept)</tt> or
+<tt>__has_extension(cxx_noexcept)</tt> to determine if support for noexcept
+exception specifications is enabled.</p>
-<h3 id="cxx_strong_enums">C++0x strongly typed enumerations</h3>
+<h4 id="cxx_strong_enums">C++0x strongly typed enumerations</h3>
-<p>Use <tt>__has_feature(cxx_strong_enums)</tt> to determine if support for
+<p>Use <tt>__has_feature(cxx_strong_enums)</tt> or
+<tt>__has_extension(cxx_strong_enums)</tt> to determine if support for
strongly typed, scoped enumerations is enabled.</p>
+<h3 id="c1x">C1X</h3>
+
+<p>The features listed below are slated for inclusion in the upcoming
+C1X standard. As a result, all these features are enabled
+with the <tt>-std=c1x</tt> option when compiling C code.</p>
+
+<h4 id="c_generic_selections">C1X generic selections</h2>
+
+<p>Use <tt>__has_feature(c_generic_selections)</tt> or
+<tt>__has_extension(c_generic_selections)</tt> to determine if support for
+generic selections is enabled.</p>
+
+<p>As an extension, the C1X generic selection expression is available in all
+languages supported by Clang. The syntax is the same as that given in the
+C1X draft standard.</p>
+
+<p>In C, type compatibility is decided according to the rules given in the
+appropriate standard, but in C++, which lacks the type compatibility rules
+used in C, types are considered compatible only if they are equivalent.</p>
+
+<h4 id="c_static_assert">C1X <tt>_Static_assert()</tt></h3>
+
+<p>Use <tt>__has_feature(c_static_assert)</tt> or
+<tt>__has_extension(c_static_assert)</tt> to determine if support for
+compile-time assertions using <tt>_Static_assert</tt> is enabled.</p>
+
<!-- ======================================================================= -->
<h2 id="checking_type_traits">Checks for Type Traits</h2>
<!-- ======================================================================= -->
-<p>Clang supports the <a hef="http://gcc.gnu.org/onlinedocs/gcc/Type-Traits.html">GNU C++ type traits</a> and a subset of the <a href="http://msdn.microsoft.com/en-us/library/ms177194(v=VS.100).aspx">Microsoft Visual C++ Type traits</a>. For each supported type trait <code>__X</code>, <code>__has_feature(X)</code> indicates the presence of the type trait. For example:
+<p>Clang supports the <a hef="http://gcc.gnu.org/onlinedocs/gcc/Type-Traits.html">GNU C++ type traits</a> and a subset of the <a href="http://msdn.microsoft.com/en-us/library/ms177194(v=VS.100).aspx">Microsoft Visual C++ Type traits</a>. For each supported type trait <code>__X</code>, <code>__has_extension(X)</code> indicates the presence of the type trait. For example:
<blockquote>
<pre>
-#if __has_feature(is_convertible_to)
+#if __has_extension(is_convertible_to)
template&lt;typename From, typename To&gt;
struct is_convertible_to {
static const bool value = __is_convertible_to(From, To);
@@ -507,7 +600,74 @@ details for the clang implementation are in <a
href="Block-ABI-Apple.txt">Block-ABI-Apple.txt</a>.</p>
-<p>Query for this feature with __has_feature(blocks).</p>
+<p>Query for this feature with __has_extension(blocks).</p>
+
+<!-- ======================================================================= -->
+<h2 id="objc_features">Objective-C Features</h2>
+<!-- ======================================================================= -->
+
+<h3 id="objc_instancetype">Related result types</h3>
+
+<p>According to Cocoa conventions, Objective-C methods with certain names ("init", "alloc", etc.) always return objects that are an instance of the receiving class's type. Such methods are said to have a "related result type", meaning that a message send to one of these methods will have the same static type as an instance of the receiver class. For example, given the following classes:</p>
+
+<blockquote>
+<pre>
+@interface NSObject
++ (id)alloc;
+- (id)init;
+@end
+
+@interface NSArray : NSObject
+@end
+</pre>
+</blockquote>
+
+<p>and this common initialization pattern</p>
+
+<blockquote>
+<pre>
+NSArray *array = [[NSArray alloc] init];
+</pre>
+</blockquote>
+
+<p>the type of the expression <code>[NSArray alloc]</code> is
+<code>NSArray*</code> because <code>alloc</code> implicitly has a
+related result type. Similarly, the type of the expression
+<code>[[NSArray alloc] init]</code> is <code>NSArray*</code>, since
+<code>init</code> has a related result type and its receiver is known
+to have the type <code>NSArray *</code>. If neither <code>alloc</code> nor <code>init</code> had a related result type, the expressions would have had type <code>id</code>, as declared in the method signature.</p>
+
+<p>To determine whether a method has a related result type, the first
+word in the camel-case selector (e.g., "init" in "initWithObjects") is
+considered, and the method will a related result type if its return
+type is compatible with the type of its class and if
+
+<ul>
+
+ <li>the first word is "alloc" or "new", and the method is a class
+ method, or</li>
+
+ <li>the first word is "autorelease", "init", "retain", or "self",
+ and the method is an instance method.</li>
+
+</ul></p>
+
+<p>If a method with a related result type is overridden by a subclass
+method, the subclass method must also return a type that is compatible
+with the subclass type. For example:</p>
+
+<blockquote>
+<pre>
+@interface NSString : NSObject
+- (NSUnrelated *)init; // incorrect usage: NSUnrelated is not NSString or a superclass of NSString
+@end
+</pre>
+</blockquote>
+
+<p>Related result types only affect the type of a message send or
+property access via the given method. In all other respects, a method
+with a related result type is treated the same way as method without a
+related result type.</p>
<!-- ======================================================================= -->
<h2 id="overloading-in-c">Function Overloading in C</h2>
@@ -607,22 +767,8 @@ caveats to this use of name mangling:</p>
C.</li>
</ul>
-<p>Query for this feature with __has_feature(attribute_overloadable).</p>
-
-
-<!-- ======================================================================= -->
-<h2 id="generic-selections">Generic Selections</h2>
-<!-- ======================================================================= -->
-
-<p>The C1X generic selection expression is available in all languages
-supported by Clang. The syntax is the same as that given in the C1X draft
-standard.</p>
-
-<p>In C, type compatibility is decided according to the rules given in the
-appropriate standard, but in C++, which lacks the type compatibility rules
-used in C, types are considered compatible only if they are equivalent.</p>
+<p>Query for this feature with __has_extension(attribute_overloadable).</p>
-<p>Query for this feature with __has_feature(generic_selections).</p>
<!-- ======================================================================= -->
<h2 id="builtins">Builtin Functions</h2>
diff --git a/docs/Makefile b/docs/Makefile
index f82d820..2608046 100644
--- a/docs/Makefile
+++ b/docs/Makefile
@@ -16,10 +16,10 @@ DOXYGEN = doxygen
$(PROJ_OBJ_DIR)/doxygen.cfg: doxygen.cfg.in
cat $< | sed \
- -e 's/@abs_top_srcdir@/../g' \
+ -e 's/@abs_srcdir@/./g' \
-e 's/@DOT@/dot/g' \
-e 's/@PACKAGE_VERSION@/mainline/' \
- -e 's/@abs_top_builddir@/../g' > $@
+ -e 's/@abs_builddir@/./g' > $@
endif
include $(CLANG_LEVEL)/Makefile
diff --git a/docs/UsersManual.html b/docs/UsersManual.html
index 73ca6c6..4962a92 100644
--- a/docs/UsersManual.html
+++ b/docs/UsersManual.html
@@ -273,6 +273,35 @@ when this is enabled, Clang will print something like:
</pre>
</dd>
<!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->
+<dt id="opt_fdiagnostics-format"><b>-fdiagnostics-format=clang/msvc/vi</b>:
+Changes diagnostic output format to better match IDEs and command line tools.</dt>
+<dd>This option controls the output format of the filename, line number, and column printed in diagnostic messages. The options, and their affect on formatting a simple conversion diagnostic, follow:
+
+ <dl>
+ <dt><b>clang</b> (default)</dt>
+ <dd>
+ <pre>t.c:3:11: warning: conversion specifies type 'char *' but the argument has type 'int'</pre>
+ </dd>
+
+ <dt><b>msvc</b></dt>
+ <dd>
+ <pre>t.c(3,11) : warning: conversion specifies type 'char *' but the argument has type 'int'</pre>
+ </dd>
+
+ <dt><b>vi</b></dt>
+ <dd>
+ <pre>t.c +3:11: warning: conversion specifies type 'char *' but the argument has type 'int'</pre>
+ </dd>
+ </dl>
+</dd>
+
+<!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->
+<dt id="opt_fdiagnostics-show-name"><b>-f[no-]diagnostics-show-name</b>:
+Enable the display of the diagnostic name.</dt>
+<dd>This option, which defaults to off, controls whether or not
+Clang prints the associated name.</dd>
+<br>
+<!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->
<dt id="opt_fdiagnostics-show-option"><b>-f[no-]diagnostics-show-option</b>:
Enable <tt>[-Woption]</tt> information in diagnostic line.</dt>
<dd>This option, which defaults to on,
@@ -499,6 +528,8 @@ it:</p>
<li>A categorization of the diagnostic as a note, warning, error, or fatal
error.</li>
<li>A text string that describes what the problem is.</li>
+<li>An option that indicates whether to print the diagnostic name [<a
+ href="#opt_fdiagnostics-show-name">-fdiagnostics-show-name</a>].</li>
<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>
diff --git a/docs/doxygen.cfg b/docs/doxygen.cfg
deleted file mode 100644
index 40180b2..0000000
--- a/docs/doxygen.cfg
+++ /dev/null
@@ -1,1230 +0,0 @@
-# Doxyfile 1.4.4
-
-# This file describes the settings to be used by the documentation system
-# doxygen (www.doxygen.org) for a project
-#
-# All text after a hash (#) is considered a comment and will be ignored
-# The format is:
-# TAG = value [value, ...]
-# For lists items can also be appended using:
-# TAG += value [value, ...]
-# Values that contain spaces should be placed between quotes (" ")
-
-#---------------------------------------------------------------------------
-# Project related configuration options
-#---------------------------------------------------------------------------
-
-# The PROJECT_NAME tag is a single word (or a sequence of words surrounded
-# by quotes) that should identify the project.
-
-PROJECT_NAME = clang
-
-# The PROJECT_NUMBER tag can be used to enter a project or revision number.
-# This could be handy for archiving the generated documentation or
-# if some version control system is used.
-
-PROJECT_NUMBER = mainline
-
-# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute)
-# base path where the generated documentation will be put.
-# If a relative path is entered, it will be relative to the location
-# where doxygen was started. If left blank the current directory will be used.
-
-OUTPUT_DIRECTORY = ../docs/doxygen
-
-# If the CREATE_SUBDIRS tag is set to YES, then doxygen will create
-# 4096 sub-directories (in 2 levels) under the output directory of each output
-# format and will distribute the generated files over these directories.
-# Enabling this option can be useful when feeding doxygen a huge amount of
-# source files, where putting all generated files in the same directory would
-# otherwise cause performance problems for the file system.
-
-CREATE_SUBDIRS = NO
-
-# The OUTPUT_LANGUAGE tag is used to specify the language in which all
-# documentation generated by doxygen is written. Doxygen will use this
-# information to generate all constant output in the proper language.
-# The default language is English, other supported languages are:
-# Brazilian, Catalan, Chinese, Chinese-Traditional, Croatian, Czech, Danish,
-# Dutch, Finnish, French, German, Greek, Hungarian, Italian, Japanese,
-# Japanese-en (Japanese with English messages), Korean, Korean-en, Norwegian,
-# Polish, Portuguese, Romanian, Russian, Serbian, Slovak, Slovene, Spanish,
-# Swedish, and Ukrainian.
-
-OUTPUT_LANGUAGE = English
-
-# This tag can be used to specify the encoding used in the generated output.
-# The encoding is not always determined by the language that is chosen,
-# but also whether or not the output is meant for Windows or non-Windows users.
-# In case there is a difference, setting the USE_WINDOWS_ENCODING tag to YES
-# forces the Windows encoding (this is the default for the Windows binary),
-# whereas setting the tag to NO uses a Unix-style encoding (the default for
-# all platforms other than Windows).
-
-USE_WINDOWS_ENCODING = NO
-
-# If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will
-# include brief member descriptions after the members that are listed in
-# the file and class documentation (similar to JavaDoc).
-# Set to NO to disable this.
-
-BRIEF_MEMBER_DESC = YES
-
-# If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend
-# the brief description of a member or function before the detailed description.
-# Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the
-# brief descriptions will be completely suppressed.
-
-REPEAT_BRIEF = YES
-
-# This tag implements a quasi-intelligent brief description abbreviator
-# that is used to form the text in various listings. Each string
-# in this list, if found as the leading text of the brief description, will be
-# stripped from the text and the result after processing the whole list, is
-# used as the annotated text. Otherwise, the brief description is used as-is.
-# If left blank, the following values are used ("$name" is automatically
-# replaced with the name of the entity): "The $name class" "The $name widget"
-# "The $name file" "is" "provides" "specifies" "contains"
-# "represents" "a" "an" "the"
-
-ABBREVIATE_BRIEF =
-
-# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then
-# Doxygen will generate a detailed section even if there is only a brief
-# description.
-
-ALWAYS_DETAILED_SEC = NO
-
-# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all
-# inherited members of a class in the documentation of that class as if those
-# members were ordinary class members. Constructors, destructors and assignment
-# operators of the base classes will not be shown.
-
-INLINE_INHERITED_MEMB = NO
-
-# If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full
-# path before files name in the file list and in the header files. If set
-# to NO the shortest path that makes the file name unique will be used.
-
-FULL_PATH_NAMES = NO
-
-# If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag
-# can be used to strip a user-defined part of the path. Stripping is
-# only done if one of the specified strings matches the left-hand part of
-# the path. The tag can be used to show relative paths in the file list.
-# If left blank the directory from which doxygen is run is used as the
-# path to strip.
-
-STRIP_FROM_PATH = ../..
-
-# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of
-# the path mentioned in the documentation of a class, which tells
-# the reader which header file to include in order to use a class.
-# If left blank only the name of the header file containing the class
-# definition is used. Otherwise one should specify the include paths that
-# are normally passed to the compiler using the -I flag.
-
-STRIP_FROM_INC_PATH =
-
-# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter
-# (but less readable) file names. This can be useful is your file systems
-# doesn't support long names like on DOS, Mac, or CD-ROM.
-
-SHORT_NAMES = NO
-
-# If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen
-# will interpret the first line (until the first dot) of a JavaDoc-style
-# comment as the brief description. If set to NO, the JavaDoc
-# comments will behave just like the Qt-style comments (thus requiring an
-# explicit @brief command for a brief description.
-
-JAVADOC_AUTOBRIEF = NO
-
-# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make Doxygen
-# treat a multi-line C++ special comment block (i.e. a block of //! or ///
-# comments) as a brief description. This used to be the default behaviour.
-# The new default is to treat a multi-line C++ comment block as a detailed
-# description. Set this tag to YES if you prefer the old behaviour instead.
-
-MULTILINE_CPP_IS_BRIEF = NO
-
-# If the DETAILS_AT_TOP tag is set to YES then Doxygen
-# will output the detailed description near the top, like JavaDoc.
-# If set to NO, the detailed description appears after the member
-# documentation.
-
-DETAILS_AT_TOP = NO
-
-# If the INHERIT_DOCS tag is set to YES (the default) then an undocumented
-# member inherits the documentation from any documented member that it
-# re-implements.
-
-INHERIT_DOCS = YES
-
-# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC
-# tag is set to YES, then doxygen will reuse the documentation of the first
-# member in the group (if any) for the other members of the group. By default
-# all members of a group must be documented explicitly.
-
-DISTRIBUTE_GROUP_DOC = NO
-
-# If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce
-# a new page for each member. If set to NO, the documentation of a member will
-# be part of the file/class/namespace that contains it.
-
-#SEPARATE_MEMBER_PAGES = NO
-
-# The TAB_SIZE tag can be used to set the number of spaces in a tab.
-# Doxygen uses this value to replace tabs by spaces in code fragments.
-
-TAB_SIZE = 2
-
-# This tag can be used to specify a number of aliases that acts
-# as commands in the documentation. An alias has the form "name=value".
-# For example adding "sideeffect=\par Side Effects:\n" will allow you to
-# put the command \sideeffect (or @sideeffect) in the documentation, which
-# will result in a user-defined paragraph with heading "Side Effects:".
-# You can put \n's in the value part of an alias to insert newlines.
-
-ALIASES =
-
-# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C
-# sources only. Doxygen will then generate output that is more tailored for C.
-# For instance, some of the names that are used will be different. The list
-# of all members will be omitted, etc.
-
-OPTIMIZE_OUTPUT_FOR_C = NO
-
-# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java sources
-# only. Doxygen will then generate output that is more tailored for Java.
-# For instance, namespaces will be presented as packages, qualified scopes
-# will look different, etc.
-
-OPTIMIZE_OUTPUT_JAVA = NO
-
-# Set the SUBGROUPING tag to YES (the default) to allow class member groups of
-# the same type (for instance a group of public functions) to be put as a
-# subgroup of that type (e.g. under the Public Functions section). Set it to
-# NO to prevent subgrouping. Alternatively, this can be done per class using
-# the \nosubgrouping command.
-
-SUBGROUPING = YES
-
-#---------------------------------------------------------------------------
-# Build related configuration options
-#---------------------------------------------------------------------------
-
-# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in
-# documentation are documented, even if no documentation was available.
-# Private class members and static file members will be hidden unless
-# the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES
-
-EXTRACT_ALL = YES
-
-# If the EXTRACT_PRIVATE tag is set to YES all private members of a class
-# will be included in the documentation.
-
-EXTRACT_PRIVATE = NO
-
-# If the EXTRACT_STATIC tag is set to YES all static members of a file
-# will be included in the documentation.
-
-EXTRACT_STATIC = YES
-
-# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs)
-# defined locally in source files will be included in the documentation.
-# If set to NO only classes defined in header files are included.
-
-EXTRACT_LOCAL_CLASSES = YES
-
-# This flag is only useful for Objective-C code. When set to YES local
-# methods, which are defined in the implementation section but not in
-# the interface are included in the documentation.
-# If set to NO (the default) only methods in the interface are included.
-
-EXTRACT_LOCAL_METHODS = NO
-
-# If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all
-# undocumented members of documented classes, files or namespaces.
-# If set to NO (the default) these members will be included in the
-# various overviews, but no documentation section is generated.
-# This option has no effect if EXTRACT_ALL is enabled.
-
-HIDE_UNDOC_MEMBERS = NO
-
-# If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all
-# undocumented classes that are normally visible in the class hierarchy.
-# If set to NO (the default) these classes will be included in the various
-# overviews. This option has no effect if EXTRACT_ALL is enabled.
-
-HIDE_UNDOC_CLASSES = NO
-
-# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, Doxygen will hide all
-# friend (class|struct|union) declarations.
-# If set to NO (the default) these declarations will be included in the
-# documentation.
-
-HIDE_FRIEND_COMPOUNDS = NO
-
-# If the HIDE_IN_BODY_DOCS tag is set to YES, Doxygen will hide any
-# documentation blocks found inside the body of a function.
-# If set to NO (the default) these blocks will be appended to the
-# function's detailed documentation block.
-
-HIDE_IN_BODY_DOCS = NO
-
-# The INTERNAL_DOCS tag determines if documentation
-# that is typed after a \internal command is included. If the tag is set
-# to NO (the default) then the documentation will be excluded.
-# Set it to YES to include the internal documentation.
-
-INTERNAL_DOCS = NO
-
-# If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate
-# file names in lower-case letters. If set to YES upper-case letters are also
-# allowed. This is useful if you have classes or files whose names only differ
-# in case and if your file system supports case sensitive file names. Windows
-# and Mac users are advised to set this option to NO.
-
-CASE_SENSE_NAMES = YES
-
-# If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen
-# will show members with their full class and namespace scopes in the
-# documentation. If set to YES the scope will be hidden.
-
-HIDE_SCOPE_NAMES = NO
-
-# If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen
-# will put a list of the files that are included by a file in the documentation
-# of that file.
-
-SHOW_INCLUDE_FILES = YES
-
-# If the INLINE_INFO tag is set to YES (the default) then a tag [inline]
-# is inserted in the documentation for inline members.
-
-INLINE_INFO = YES
-
-# If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen
-# will sort the (detailed) documentation of file and class members
-# alphabetically by member name. If set to NO the members will appear in
-# declaration order.
-
-SORT_MEMBER_DOCS = YES
-
-# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the
-# brief documentation of file, namespace and class members alphabetically
-# by member name. If set to NO (the default) the members will appear in
-# declaration order.
-
-SORT_BRIEF_DOCS = NO
-
-# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be
-# sorted by fully-qualified names, including namespaces. If set to
-# NO (the default), the class list will be sorted only by class name,
-# not including the namespace part.
-# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES.
-# Note: This option applies only to the class list, not to the
-# alphabetical list.
-
-SORT_BY_SCOPE_NAME = NO
-
-# The GENERATE_TODOLIST tag can be used to enable (YES) or
-# disable (NO) the todo list. This list is created by putting \todo
-# commands in the documentation.
-
-GENERATE_TODOLIST = YES
-
-# The GENERATE_TESTLIST tag can be used to enable (YES) or
-# disable (NO) the test list. This list is created by putting \test
-# commands in the documentation.
-
-GENERATE_TESTLIST = YES
-
-# The GENERATE_BUGLIST tag can be used to enable (YES) or
-# disable (NO) the bug list. This list is created by putting \bug
-# commands in the documentation.
-
-GENERATE_BUGLIST = YES
-
-# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or
-# disable (NO) the deprecated list. This list is created by putting
-# \deprecated commands in the documentation.
-
-GENERATE_DEPRECATEDLIST= YES
-
-# The ENABLED_SECTIONS tag can be used to enable conditional
-# documentation sections, marked by \if sectionname ... \endif.
-
-ENABLED_SECTIONS =
-
-# The MAX_INITIALIZER_LINES tag determines the maximum number of lines
-# the initial value of a variable or define consists of for it to appear in
-# the documentation. If the initializer consists of more lines than specified
-# here it will be hidden. Use a value of 0 to hide initializers completely.
-# The appearance of the initializer of individual variables and defines in the
-# documentation can be controlled using \showinitializer or \hideinitializer
-# command in the documentation regardless of this setting.
-
-MAX_INITIALIZER_LINES = 30
-
-# Set the SHOW_USED_FILES tag to NO to disable the list of files generated
-# at the bottom of the documentation of classes and structs. If set to YES the
-# list will mention the files that were used to generate the documentation.
-
-SHOW_USED_FILES = YES
-
-# If the sources in your project are distributed over multiple directories
-# then setting the SHOW_DIRECTORIES tag to YES will show the directory hierarchy
-# in the documentation. The default is YES.
-
-SHOW_DIRECTORIES = YES
-
-# The FILE_VERSION_FILTER tag can be used to specify a program or script that
-# doxygen should invoke to get the current version for each file (typically from the
-# version control system). Doxygen will invoke the program by executing (via
-# popen()) the command <command> <input-file>, where <command> is the value of
-# the FILE_VERSION_FILTER tag, and <input-file> is the name of an input file
-# provided by doxygen. Whatever the progam writes to standard output
-# is used as the file version. See the manual for examples.
-
-#FILE_VERSION_FILTER =
-
-#---------------------------------------------------------------------------
-# configuration options related to warning and progress messages
-#---------------------------------------------------------------------------
-
-# The QUIET tag can be used to turn on/off the messages that are generated
-# by doxygen. Possible values are YES and NO. If left blank NO is used.
-
-QUIET = NO
-
-# The WARNINGS tag can be used to turn on/off the warning messages that are
-# generated by doxygen. Possible values are YES and NO. If left blank
-# NO is used.
-
-WARNINGS = NO
-
-# If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings
-# for undocumented members. If EXTRACT_ALL is set to YES then this flag will
-# automatically be disabled.
-
-WARN_IF_UNDOCUMENTED = NO
-
-# If WARN_IF_DOC_ERROR is set to YES, doxygen will generate warnings for
-# potential errors in the documentation, such as not documenting some
-# parameters in a documented function, or documenting parameters that
-# don't exist or using markup commands wrongly.
-
-WARN_IF_DOC_ERROR = YES
-
-# This WARN_NO_PARAMDOC option can be abled to get warnings for
-# functions that are documented, but have no documentation for their parameters
-# or return value. If set to NO (the default) doxygen will only warn about
-# wrong or incomplete parameter documentation, but not about the absence of
-# documentation.
-
-#WARN_NO_PARAMDOC = NO
-
-# The WARN_FORMAT tag determines the format of the warning messages that
-# doxygen can produce. The string should contain the $file, $line, and $text
-# tags, which will be replaced by the file and line number from which the
-# warning originated and the warning text. Optionally the format may contain
-# $version, which will be replaced by the version of the file (if it could
-# be obtained via FILE_VERSION_FILTER)
-
-WARN_FORMAT =
-
-# The WARN_LOGFILE tag can be used to specify a file to which warning
-# and error messages should be written. If left blank the output is written
-# to stderr.
-
-WARN_LOGFILE =
-
-#---------------------------------------------------------------------------
-# configuration options related to the input files
-#---------------------------------------------------------------------------
-
-# The INPUT tag can be used to specify the files and/or directories that contain
-# documented source files. You may enter file names like "myfile.cpp" or
-# directories like "/usr/src/myproject". Separate the files or directories
-# with spaces.
-
-INPUT = ../include \
- ../lib \
- ../docs/doxygen.intro
-
-# If the value of the INPUT tag contains directories, you can use the
-# FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp
-# and *.h) to filter out the source-files in the directories. If left
-# blank the following patterns are tested:
-# *.c *.cc *.cxx *.cpp *.c++ *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh *.hxx
-# *.hpp *.h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm
-
-FILE_PATTERNS =
-
-# The RECURSIVE tag can be used to turn specify whether or not subdirectories
-# should be searched for input files as well. Possible values are YES and NO.
-# If left blank NO is used.
-
-RECURSIVE = YES
-
-# The EXCLUDE tag can be used to specify files and/or directories that should
-# excluded from the INPUT source files. This way you can easily exclude a
-# subdirectory from a directory tree whose root is specified with the INPUT tag.
-
-EXCLUDE =
-
-# The EXCLUDE_SYMLINKS tag can be used select whether or not files or
-# directories that are symbolic links (a Unix filesystem feature) are excluded
-# from the input.
-
-EXCLUDE_SYMLINKS = NO
-
-# If the value of the INPUT tag contains directories, you can use the
-# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude
-# certain files from those directories. Note that the wildcards are matched
-# against the file with absolute path, so to exclude all test directories
-# for example use the pattern */test/*
-
-EXCLUDE_PATTERNS =
-
-# The EXAMPLE_PATH tag can be used to specify one or more files or
-# directories that contain example code fragments that are included (see
-# the \include command).
-
-EXAMPLE_PATH = ../examples
-
-# If the value of the EXAMPLE_PATH tag contains directories, you can use the
-# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp
-# and *.h) to filter out the source-files in the directories. If left
-# blank all files are included.
-
-EXAMPLE_PATTERNS =
-
-# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be
-# searched for input files to be used with the \include or \dontinclude
-# commands irrespective of the value of the RECURSIVE tag.
-# Possible values are YES and NO. If left blank NO is used.
-
-EXAMPLE_RECURSIVE = YES
-
-# The IMAGE_PATH tag can be used to specify one or more files or
-# directories that contain image that are included in the documentation (see
-# the \image command).
-
-IMAGE_PATH = ../docs/img
-
-# The INPUT_FILTER tag can be used to specify a program that doxygen should
-# invoke to filter for each input file. Doxygen will invoke the filter program
-# by executing (via popen()) the command <filter> <input-file>, where <filter>
-# is the value of the INPUT_FILTER tag, and <input-file> is the name of an
-# input file. Doxygen will then use the output that the filter program writes
-# to standard output. If FILTER_PATTERNS is specified, this tag will be
-# ignored.
-
-INPUT_FILTER =
-
-# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern
-# basis. Doxygen will compare the file name with each pattern and apply the
-# filter if there is a match. The filters are a list of the form:
-# pattern=filter (like *.cpp=my_cpp_filter). See INPUT_FILTER for further
-# info on how filters are used. If FILTER_PATTERNS is empty, INPUT_FILTER
-# is applied to all files.
-
-FILTER_PATTERNS =
-
-# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using
-# INPUT_FILTER) will be used to filter the input files when producing source
-# files to browse (i.e. when SOURCE_BROWSER is set to YES).
-
-FILTER_SOURCE_FILES = NO
-
-#---------------------------------------------------------------------------
-# configuration options related to source browsing
-#---------------------------------------------------------------------------
-
-# If the SOURCE_BROWSER tag is set to YES then a list of source files will
-# be generated. Documented entities will be cross-referenced with these sources.
-# Note: To get rid of all source code in the generated output, make sure also
-# VERBATIM_HEADERS is set to NO.
-
-SOURCE_BROWSER = YES
-
-# Setting the INLINE_SOURCES tag to YES will include the body
-# of functions and classes directly in the documentation.
-
-INLINE_SOURCES = NO
-
-# Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct
-# doxygen to hide any special comment blocks from generated source code
-# fragments. Normal C and C++ comments will always remain visible.
-
-STRIP_CODE_COMMENTS = NO
-
-# If the REFERENCED_BY_RELATION tag is set to YES (the default)
-# then for each documented function all documented
-# functions referencing it will be listed.
-
-REFERENCED_BY_RELATION = YES
-
-# If the REFERENCES_RELATION tag is set to YES (the default)
-# then for each documented function all documented entities
-# called/used by that function will be listed.
-
-REFERENCES_RELATION = YES
-
-# If the USE_HTAGS tag is set to YES then the references to source code
-# will point to the HTML generated by the htags(1) tool instead of doxygen
-# built-in source browser. The htags tool is part of GNU's global source
-# tagging system (see http://www.gnu.org/software/global/global.html). You
-# will need version 4.8.6 or higher.
-
-#USE_HTAGS = NO
-
-# If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen
-# will generate a verbatim copy of the header file for each class for
-# which an include is specified. Set to NO to disable this.
-
-VERBATIM_HEADERS = YES
-
-#---------------------------------------------------------------------------
-# configuration options related to the alphabetical class index
-#---------------------------------------------------------------------------
-
-# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index
-# of all compounds will be generated. Enable this if the project
-# contains a lot of classes, structs, unions or interfaces.
-
-ALPHABETICAL_INDEX = YES
-
-# If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then
-# the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns
-# in which this list will be split (can be a number in the range [1..20])
-
-COLS_IN_ALPHA_INDEX = 4
-
-# In case all classes in a project start with a common prefix, all
-# classes will be put under the same header in the alphabetical index.
-# The IGNORE_PREFIX tag can be used to specify one or more prefixes that
-# should be ignored while generating the index headers.
-
-IGNORE_PREFIX = llvm::
-
-#---------------------------------------------------------------------------
-# configuration options related to the HTML output
-#---------------------------------------------------------------------------
-
-# If the GENERATE_HTML tag is set to YES (the default) Doxygen will
-# generate HTML output.
-
-GENERATE_HTML = YES
-
-# The HTML_OUTPUT tag is used to specify where the HTML docs will be put.
-# If a relative path is entered the value of OUTPUT_DIRECTORY will be
-# put in front of it. If left blank `html' will be used as the default path.
-
-HTML_OUTPUT = html
-
-# The HTML_FILE_EXTENSION tag can be used to specify the file extension for
-# each generated HTML page (for example: .htm,.php,.asp). If it is left blank
-# doxygen will generate files with .html extension.
-
-HTML_FILE_EXTENSION = .html
-
-# The HTML_HEADER tag can be used to specify a personal HTML header for
-# each generated HTML page. If it is left blank doxygen will generate a
-# standard header.
-
-HTML_HEADER = ../docs/doxygen.header
-
-# The HTML_FOOTER tag can be used to specify a personal HTML footer for
-# each generated HTML page. If it is left blank doxygen will generate a
-# standard footer.
-
-HTML_FOOTER = ../docs/doxygen.footer
-
-# The HTML_STYLESHEET tag can be used to specify a user-defined cascading
-# style sheet that is used by each HTML page. It can be used to
-# fine-tune the look of the HTML output. If the tag is left blank doxygen
-# will generate a default style sheet. Note that doxygen will try to copy
-# the style sheet file to the HTML output directory, so don't put your own
-# stylesheet in the HTML output directory as well, or it will be erased!
-
-HTML_STYLESHEET = ../docs/doxygen.css
-
-# If the HTML_ALIGN_MEMBERS tag is set to YES, the members of classes,
-# files or namespaces will be aligned in HTML using tables. If set to
-# NO a bullet list will be used.
-
-HTML_ALIGN_MEMBERS = YES
-
-# If the GENERATE_HTMLHELP tag is set to YES, additional index files
-# will be generated that can be used as input for tools like the
-# Microsoft HTML help workshop to generate a compressed HTML help file (.chm)
-# of the generated HTML documentation.
-
-GENERATE_HTMLHELP = NO
-
-# If the GENERATE_HTMLHELP tag is set to YES, the CHM_FILE tag can
-# be used to specify the file name of the resulting .chm file. You
-# can add a path in front of the file if the result should not be
-# written to the html output directory.
-
-CHM_FILE =
-
-# If the GENERATE_HTMLHELP tag is set to YES, the HHC_LOCATION tag can
-# be used to specify the location (absolute path including file name) of
-# the HTML help compiler (hhc.exe). If non-empty doxygen will try to run
-# the HTML help compiler on the generated index.hhp.
-
-HHC_LOCATION =
-
-# If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag
-# controls if a separate .chi index file is generated (YES) or that
-# it should be included in the master .chm file (NO).
-
-GENERATE_CHI = NO
-
-# If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag
-# controls whether a binary table of contents is generated (YES) or a
-# normal table of contents (NO) in the .chm file.
-
-BINARY_TOC = NO
-
-# The TOC_EXPAND flag can be set to YES to add extra items for group members
-# to the contents of the HTML help documentation and to the tree view.
-
-TOC_EXPAND = NO
-
-# The DISABLE_INDEX tag can be used to turn on/off the condensed index at
-# top of each HTML page. The value NO (the default) enables the index and
-# the value YES disables it.
-
-DISABLE_INDEX = NO
-
-# This tag can be used to set the number of enum values (range [1..20])
-# that doxygen will group on one line in the generated HTML documentation.
-
-ENUM_VALUES_PER_LINE = 4
-
-# If the GENERATE_TREEVIEW tag is set to YES, a side panel will be
-# generated containing a tree-like index structure (just like the one that
-# is generated for HTML Help). For this to work a browser that supports
-# JavaScript, DHTML, CSS and frames is required (for instance Mozilla 1.0+,
-# Netscape 6.0+, Internet explorer 5.0+, or Konqueror). Windows users are
-# probably better off using the HTML help feature.
-
-GENERATE_TREEVIEW = NO
-
-# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be
-# used to set the initial width (in pixels) of the frame in which the tree
-# is shown.
-
-TREEVIEW_WIDTH = 250
-
-#---------------------------------------------------------------------------
-# configuration options related to the LaTeX output
-#---------------------------------------------------------------------------
-
-# If the GENERATE_LATEX tag is set to YES (the default) Doxygen will
-# generate Latex output.
-
-GENERATE_LATEX = NO
-
-# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put.
-# If a relative path is entered the value of OUTPUT_DIRECTORY will be
-# put in front of it. If left blank `latex' will be used as the default path.
-
-LATEX_OUTPUT =
-
-# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be
-# invoked. If left blank `latex' will be used as the default command name.
-
-LATEX_CMD_NAME = latex
-
-# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to
-# generate index for LaTeX. If left blank `makeindex' will be used as the
-# default command name.
-
-MAKEINDEX_CMD_NAME = makeindex
-
-# If the COMPACT_LATEX tag is set to YES Doxygen generates more compact
-# LaTeX documents. This may be useful for small projects and may help to
-# save some trees in general.
-
-COMPACT_LATEX = NO
-
-# The PAPER_TYPE tag can be used to set the paper type that is used
-# by the printer. Possible values are: a4, a4wide, letter, legal and
-# executive. If left blank a4wide will be used.
-
-PAPER_TYPE = letter
-
-# The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX
-# packages that should be included in the LaTeX output.
-
-EXTRA_PACKAGES =
-
-# The LATEX_HEADER tag can be used to specify a personal LaTeX header for
-# the generated latex document. The header should contain everything until
-# the first chapter. If it is left blank doxygen will generate a
-# standard header. Notice: only use this tag if you know what you are doing!
-
-LATEX_HEADER =
-
-# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated
-# is prepared for conversion to pdf (using ps2pdf). The pdf file will
-# contain links (just like the HTML output) instead of page references
-# This makes the output suitable for online browsing using a pdf viewer.
-
-PDF_HYPERLINKS = NO
-
-# If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of
-# plain latex in the generated Makefile. Set this option to YES to get a
-# higher quality PDF documentation.
-
-USE_PDFLATEX = NO
-
-# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode.
-# command to the generated LaTeX files. This will instruct LaTeX to keep
-# running if errors occur, instead of asking the user for help.
-# This option is also used when generating formulas in HTML.
-
-LATEX_BATCHMODE = NO
-
-# If LATEX_HIDE_INDICES is set to YES then doxygen will not
-# include the index chapters (such as File Index, Compound Index, etc.)
-# in the output.
-
-LATEX_HIDE_INDICES = NO
-
-#---------------------------------------------------------------------------
-# configuration options related to the RTF output
-#---------------------------------------------------------------------------
-
-# If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output
-# The RTF output is optimized for Word 97 and may not look very pretty with
-# other RTF readers or editors.
-
-GENERATE_RTF = NO
-
-# The RTF_OUTPUT tag is used to specify where the RTF docs will be put.
-# If a relative path is entered the value of OUTPUT_DIRECTORY will be
-# put in front of it. If left blank `rtf' will be used as the default path.
-
-RTF_OUTPUT =
-
-# If the COMPACT_RTF tag is set to YES Doxygen generates more compact
-# RTF documents. This may be useful for small projects and may help to
-# save some trees in general.
-
-COMPACT_RTF = NO
-
-# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated
-# will contain hyperlink fields. The RTF file will
-# contain links (just like the HTML output) instead of page references.
-# This makes the output suitable for online browsing using WORD or other
-# programs which support those fields.
-# Note: wordpad (write) and others do not support links.
-
-RTF_HYPERLINKS = NO
-
-# Load stylesheet definitions from file. Syntax is similar to doxygen's
-# config file, i.e. a series of assignments. You only have to provide
-# replacements, missing definitions are set to their default value.
-
-RTF_STYLESHEET_FILE =
-
-# Set optional variables used in the generation of an rtf document.
-# Syntax is similar to doxygen's config file.
-
-RTF_EXTENSIONS_FILE =
-
-#---------------------------------------------------------------------------
-# configuration options related to the man page output
-#---------------------------------------------------------------------------
-
-# If the GENERATE_MAN tag is set to YES (the default) Doxygen will
-# generate man pages
-
-GENERATE_MAN = NO
-
-# The MAN_OUTPUT tag is used to specify where the man pages will be put.
-# If a relative path is entered the value of OUTPUT_DIRECTORY will be
-# put in front of it. If left blank `man' will be used as the default path.
-
-MAN_OUTPUT =
-
-# The MAN_EXTENSION tag determines the extension that is added to
-# the generated man pages (default is the subroutine's section .3)
-
-MAN_EXTENSION =
-
-# If the MAN_LINKS tag is set to YES and Doxygen generates man output,
-# then it will generate one additional man file for each entity
-# documented in the real man page(s). These additional files
-# only source the real man page, but without them the man command
-# would be unable to find the correct page. The default is NO.
-
-MAN_LINKS = NO
-
-#---------------------------------------------------------------------------
-# configuration options related to the XML output
-#---------------------------------------------------------------------------
-
-# If the GENERATE_XML tag is set to YES Doxygen will
-# generate an XML file that captures the structure of
-# the code including all documentation.
-
-GENERATE_XML = NO
-
-# The XML_OUTPUT tag is used to specify where the XML pages will be put.
-# If a relative path is entered the value of OUTPUT_DIRECTORY will be
-# put in front of it. If left blank `xml' will be used as the default path.
-
-XML_OUTPUT = xml
-
-# The XML_SCHEMA tag can be used to specify an XML schema,
-# which can be used by a validating XML parser to check the
-# syntax of the XML files.
-
-XML_SCHEMA =
-
-# The XML_DTD tag can be used to specify an XML DTD,
-# which can be used by a validating XML parser to check the
-# syntax of the XML files.
-
-XML_DTD =
-
-# If the XML_PROGRAMLISTING tag is set to YES Doxygen will
-# dump the program listings (including syntax highlighting
-# and cross-referencing information) to the XML output. Note that
-# enabling this will significantly increase the size of the XML output.
-
-XML_PROGRAMLISTING = YES
-
-#---------------------------------------------------------------------------
-# configuration options for the AutoGen Definitions output
-#---------------------------------------------------------------------------
-
-# If the GENERATE_AUTOGEN_DEF tag is set to YES Doxygen will
-# generate an AutoGen Definitions (see autogen.sf.net) file
-# that captures the structure of the code including all
-# documentation. Note that this feature is still experimental
-# and incomplete at the moment.
-
-GENERATE_AUTOGEN_DEF = NO
-
-#---------------------------------------------------------------------------
-# configuration options related to the Perl module output
-#---------------------------------------------------------------------------
-
-# If the GENERATE_PERLMOD tag is set to YES Doxygen will
-# generate a Perl module file that captures the structure of
-# the code including all documentation. Note that this
-# feature is still experimental and incomplete at the
-# moment.
-
-GENERATE_PERLMOD = NO
-
-# If the PERLMOD_LATEX tag is set to YES Doxygen will generate
-# the necessary Makefile rules, Perl scripts and LaTeX code to be able
-# to generate PDF and DVI output from the Perl module output.
-
-PERLMOD_LATEX = NO
-
-# If the PERLMOD_PRETTY tag is set to YES the Perl module output will be
-# nicely formatted so it can be parsed by a human reader. This is useful
-# if you want to understand what is going on. On the other hand, if this
-# tag is set to NO the size of the Perl module output will be much smaller
-# and Perl will parse it just the same.
-
-PERLMOD_PRETTY = YES
-
-# The names of the make variables in the generated doxyrules.make file
-# are prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX.
-# This is useful so different doxyrules.make files included by the same
-# Makefile don't overwrite each other's variables.
-
-PERLMOD_MAKEVAR_PREFIX =
-
-#---------------------------------------------------------------------------
-# Configuration options related to the preprocessor
-#---------------------------------------------------------------------------
-
-# If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will
-# evaluate all C-preprocessor directives found in the sources and include
-# files.
-
-ENABLE_PREPROCESSING = YES
-
-# If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro
-# names in the source code. If set to NO (the default) only conditional
-# compilation will be performed. Macro expansion can be done in a controlled
-# way by setting EXPAND_ONLY_PREDEF to YES.
-
-MACRO_EXPANSION = NO
-
-# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES
-# then the macro expansion is limited to the macros specified with the
-# PREDEFINED and EXPAND_AS_PREDEFINED tags.
-
-EXPAND_ONLY_PREDEF = NO
-
-# If the SEARCH_INCLUDES tag is set to YES (the default) the includes files
-# in the INCLUDE_PATH (see below) will be search if a #include is found.
-
-SEARCH_INCLUDES = YES
-
-# The INCLUDE_PATH tag can be used to specify one or more directories that
-# contain include files that are not input files but should be processed by
-# the preprocessor.
-
-INCLUDE_PATH = ../include
-
-# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard
-# patterns (like *.h and *.hpp) to filter out the header-files in the
-# directories. If left blank, the patterns specified with FILE_PATTERNS will
-# be used.
-
-INCLUDE_FILE_PATTERNS =
-
-# The PREDEFINED tag can be used to specify one or more macro names that
-# are defined before the preprocessor is started (similar to the -D option of
-# gcc). The argument of the tag is a list of macros of the form: name
-# or name=definition (no spaces). If the definition and the = are
-# omitted =1 is assumed. To prevent a macro definition from being
-# undefined via #undef or recursively expanded use the := operator
-# instead of the = operator.
-
-PREDEFINED =
-
-# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then
-# this tag can be used to specify a list of macro names that should be expanded.
-# The macro definition that is found in the sources will be used.
-# Use the PREDEFINED tag if you want to use a different macro definition.
-
-EXPAND_AS_DEFINED =
-
-# If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then
-# doxygen's preprocessor will remove all function-like macros that are alone
-# on a line, have an all uppercase name, and do not end with a semicolon. Such
-# function macros are typically used for boiler-plate code, and will confuse
-# the parser if not removed.
-
-SKIP_FUNCTION_MACROS = YES
-
-#---------------------------------------------------------------------------
-# Configuration::additions related to external references
-#---------------------------------------------------------------------------
-
-# The TAGFILES option can be used to specify one or more tagfiles.
-# Optionally an initial location of the external documentation
-# can be added for each tagfile. The format of a tag file without
-# this location is as follows:
-# TAGFILES = file1 file2 ...
-# Adding location for the tag files is done as follows:
-# TAGFILES = file1=loc1 "file2 = loc2" ...
-# where "loc1" and "loc2" can be relative or absolute paths or
-# URLs. If a location is present for each tag, the installdox tool
-# does not have to be run to correct the links.
-# Note that each tag file must have a unique name
-# (where the name does NOT include the path)
-# If a tag file is not located in the directory in which doxygen
-# is run, you must also specify the path to the tagfile here.
-
-TAGFILES =
-
-# When a file name is specified after GENERATE_TAGFILE, doxygen will create
-# a tag file that is based on the input files it reads.
-
-GENERATE_TAGFILE =
-
-# If the ALLEXTERNALS tag is set to YES all external classes will be listed
-# in the class index. If set to NO only the inherited external classes
-# will be listed.
-
-ALLEXTERNALS = YES
-
-# If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed
-# in the modules index. If set to NO, only the current project's groups will
-# be listed.
-
-EXTERNAL_GROUPS = YES
-
-# The PERL_PATH should be the absolute path and name of the perl script
-# interpreter (i.e. the result of `which perl').
-
-PERL_PATH =
-
-#---------------------------------------------------------------------------
-# Configuration options related to the dot tool
-#---------------------------------------------------------------------------
-
-# If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will
-# generate a inheritance diagram (in HTML, RTF and LaTeX) for classes with base
-# or super classes. Setting the tag to NO turns the diagrams off. Note that
-# this option is superseded by the HAVE_DOT option below. This is only a
-# fallback. It is recommended to install and use dot, since it yields more
-# powerful graphs.
-
-CLASS_DIAGRAMS = YES
-
-# If set to YES, the inheritance and collaboration graphs will hide
-# inheritance and usage relations if the target is undocumented
-# or is not a class.
-
-HIDE_UNDOC_RELATIONS = NO
-
-# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is
-# available from the path. This tool is part of Graphviz, a graph visualization
-# toolkit from AT&T and Lucent Bell Labs. The other options in this section
-# have no effect if this option is set to NO (the default)
-
-HAVE_DOT = YES
-
-# If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen
-# will generate a graph for each documented class showing the direct and
-# indirect inheritance relations. Setting this tag to YES will force the
-# the CLASS_DIAGRAMS tag to NO.
-
-CLASS_GRAPH = YES
-
-# If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen
-# will generate a graph for each documented class showing the direct and
-# indirect implementation dependencies (inheritance, containment, and
-# class references variables) of the class with other documented classes.
-
-COLLABORATION_GRAPH = YES
-
-# If the GROUP_GRAPHS and HAVE_DOT tags are set to YES then doxygen
-# will generate a graph for groups, showing the direct groups dependencies
-
-#GROUP_GRAPHS = YES
-
-# If the UML_LOOK tag is set to YES doxygen will generate inheritance and
-# collaboration diagrams in a style similar to the OMG's Unified Modeling
-# Language.
-
-UML_LOOK = NO
-
-# If set to YES, the inheritance and collaboration graphs will show the
-# relations between templates and their instances.
-
-TEMPLATE_RELATIONS = YES
-
-# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT
-# tags are set to YES then doxygen will generate a graph for each documented
-# file showing the direct and indirect include dependencies of the file with
-# other documented files.
-
-INCLUDE_GRAPH = YES
-
-# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and
-# HAVE_DOT tags are set to YES then doxygen will generate a graph for each
-# documented header file showing the documented files that directly or
-# indirectly include this file.
-
-INCLUDED_BY_GRAPH = YES
-
-# If the CALL_GRAPH and HAVE_DOT tags are set to YES then doxygen will
-# generate a call dependency graph for every global function or class method.
-# Note that enabling this option will significantly increase the time of a run.
-# So in most cases it will be better to enable call graphs for selected
-# functions only using the \callgraph command.
-
-CALL_GRAPH = NO
-
-# If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen
-# will graphical hierarchy of all classes instead of a textual one.
-
-GRAPHICAL_HIERARCHY = YES
-
-# If the DIRECTORY_GRAPH, SHOW_DIRECTORIES and HAVE_DOT tags are set to YES
-# then doxygen will show the dependencies a directory has on other directories
-# in a graphical way. The dependency relations are determined by the #include
-# relations between the files in the directories.
-
-#DIRECTORY_GRAPH = YES
-
-# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images
-# generated by dot. Possible values are png, jpg, or gif
-# If left blank png will be used.
-
-DOT_IMAGE_FORMAT = png
-
-# The tag DOT_PATH can be used to specify the path where the dot tool can be
-# found. If left blank, it is assumed the dot tool can be found in the path.
-
-DOT_PATH = dot
-
-# The DOTFILE_DIRS tag can be used to specify one or more directories that
-# contain dot files that are included in the documentation (see the
-# \dotfile command).
-
-DOTFILE_DIRS =
-
-# The MAX_DOT_GRAPH_WIDTH tag can be used to set the maximum allowed width
-# (in pixels) of the graphs generated by dot. If a graph becomes larger than
-# this value, doxygen will try to truncate the graph, so that it fits within
-# the specified constraint. Beware that most browsers cannot cope with very
-# large images.
-
-MAX_DOT_GRAPH_WIDTH = 1024
-
-# The MAX_DOT_GRAPH_HEIGHT tag can be used to set the maximum allows height
-# (in pixels) of the graphs generated by dot. If a graph becomes larger than
-# this value, doxygen will try to truncate the graph, so that it fits within
-# the specified constraint. Beware that most browsers cannot cope with very
-# large images.
-
-MAX_DOT_GRAPH_HEIGHT = 1024
-
-# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the
-# graphs generated by dot. A depth value of 3 means that only nodes reachable
-# from the root by following a path via at most 3 edges will be shown. Nodes
-# that lay further from the root node will be omitted. Note that setting this
-# option to 1 or 2 may greatly reduce the computation time needed for large
-# code bases. Also note that a graph may be further truncated if the graph's
-# image dimensions are not sufficient to fit the graph (see MAX_DOT_GRAPH_WIDTH
-# and MAX_DOT_GRAPH_HEIGHT). If 0 is used for the depth value (the default),
-# the graph is not depth-constrained.
-
-MAX_DOT_GRAPH_DEPTH = 0
-
-# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent
-# background. This is disabled by default, which results in a white background.
-# Warning: Depending on the platform used, enabling this option may lead to
-# badly anti-aliased labels on the edges of a graph (i.e. they become hard to
-# read).
-
-#DOT_TRANSPARENT = NO
-
-# Set the DOT_MULTI_TARGETS tag to YES allow dot to generate multiple output
-# files in one run (i.e. multiple -o and -T options on the command line). This
-# makes dot run faster, but since only newer versions of dot (>1.8.10)
-# support this, this feature is disabled by default.
-
-#DOT_MULTI_TARGETS = NO
-
-# If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will
-# generate a legend page explaining the meaning of the various boxes and
-# arrows in the dot generated graphs.
-
-GENERATE_LEGEND = YES
-
-# If the DOT_CLEANUP tag is set to YES (the default) Doxygen will
-# remove the intermediate dot files that are used to generate
-# the various graphs.
-
-DOT_CLEANUP = YES
-
-#---------------------------------------------------------------------------
-# Configuration::additions related to the search engine
-#---------------------------------------------------------------------------
-
-# The SEARCHENGINE tag specifies whether or not a search engine should be
-# used. If set to NO the values of all tags below this one will be ignored.
-
-SEARCHENGINE = NO
diff --git a/docs/doxygen.cfg.in b/docs/doxygen.cfg.in
index c1130fb..ed9ffcb 100644
--- a/docs/doxygen.cfg.in
+++ b/docs/doxygen.cfg.in
@@ -30,7 +30,7 @@ PROJECT_NUMBER = @PACKAGE_VERSION@
# If a relative path is entered, it will be relative to the location
# where doxygen was started. If left blank the current directory will be used.
-OUTPUT_DIRECTORY = @abs_top_builddir@/docs/doxygen
+OUTPUT_DIRECTORY = @abs_builddir@/doxygen
# If the CREATE_SUBDIRS tag is set to YES, then doxygen will create
# 4096 sub-directories (in 2 levels) under the output directory of each output
@@ -450,9 +450,9 @@ WARN_LOGFILE =
# directories like "/usr/src/myproject". Separate the files or directories
# with spaces.
-INPUT = @abs_top_srcdir@/include \
- @abs_top_srcdir@/lib \
- @abs_top_srcdir@/docs/doxygen.intro
+INPUT = @abs_srcdir@/../include \
+ @abs_srcdir@/../lib \
+ @abs_srcdir@/doxygen.intro
# If the value of the INPUT tag contains directories, you can use the
# FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp
@@ -493,7 +493,7 @@ EXCLUDE_PATTERNS =
# directories that contain example code fragments that are included (see
# the \include command).
-EXAMPLE_PATH = @abs_top_srcdir@/examples
+EXAMPLE_PATH = @abs_srcdir@/../examples
# If the value of the EXAMPLE_PATH tag contains directories, you can use the
# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp
@@ -513,7 +513,7 @@ EXAMPLE_RECURSIVE = YES
# directories that contain image that are included in the documentation (see
# the \image command).
-IMAGE_PATH = @abs_top_srcdir@/docs/img
+IMAGE_PATH = @abs_srcdir@/img
# The INPUT_FILTER tag can be used to specify a program that doxygen should
# invoke to filter for each input file. Doxygen will invoke the filter program
@@ -636,13 +636,13 @@ HTML_FILE_EXTENSION = .html
# each generated HTML page. If it is left blank doxygen will generate a
# standard header.
-HTML_HEADER = @abs_top_srcdir@/docs/doxygen.header
+HTML_HEADER = @abs_srcdir@/doxygen.header
# The HTML_FOOTER tag can be used to specify a personal HTML footer for
# each generated HTML page. If it is left blank doxygen will generate a
# standard footer.
-HTML_FOOTER = @abs_top_srcdir@/docs/doxygen.footer
+HTML_FOOTER = @abs_srcdir@/doxygen.footer
# The HTML_STYLESHEET tag can be used to specify a user-defined cascading
# style sheet that is used by each HTML page. It can be used to
@@ -651,7 +651,7 @@ HTML_FOOTER = @abs_top_srcdir@/docs/doxygen.footer
# the style sheet file to the HTML output directory, so don't put your own
# stylesheet in the HTML output directory as well, or it will be erased!
-HTML_STYLESHEET = @abs_top_srcdir@/docs/doxygen.css
+HTML_STYLESHEET = @abs_srcdir@/doxygen.css
# If the HTML_ALIGN_MEMBERS tag is set to YES, the members of classes,
# files or namespaces will be aligned in HTML using tables. If set to
diff --git a/docs/libIndex.html b/docs/libIndex.html
deleted file mode 100644
index e722ee1..0000000
--- a/docs/libIndex.html
+++ /dev/null
@@ -1,267 +0,0 @@
-<html>
-<head>
- <title>The Index Library</title>
- <link type="text/css" rel="stylesheet" href="../menu.css" />
- <link type="text/css" rel="stylesheet" href="../content.css" />
- <style type="text/css">
- td {
- vertical-align: top;
- }
- </style>
-</head>
-
-<body>
-
-<!--#include virtual="../menu.html.incl"-->
-
-<div id="content">
-
-<h1>The Index Library</h1>
-
- <p><b>Table of Contents</b></p>
- <ul>
- <li><a href="#philosophy">Design Philosophy</a></li>
- <li><a href="#classes">Classes</a>
- <ul>
- <li><a href="#entity">Entity</a></li>
- <li><a href="#astlocation">ASTLocation</a></li>
- <li><a href="#declreferencemap">DeclReferenceMap</a></li>
- </ul>
- </li>
- <li><a href="#functions">Functions</a>
- <ul>
- <li><a href="#resolveloc">ResolveLocationInAST</a></li>
- </ul>
- </li>
- <li><a href="#astfiles">AST Files</a></li>
- <li><a href="#indextest">index-test tool</a>
- <ul>
- <li><a href="#indextestusage">Usage</a></li>
- <li><a href="#indextestexamples">Examples</a></li>
- </ul>
- </li>
-</ul>
-
-<h2 id="philosophy">Design Philosophy</h2>
-
-<p> The Index library is meant to provide the basic infrastructure for
- cross-translation-unit analysis and is primarily focused on indexing
- related functionality. It provides an API for clients that need to
- accurately map the AST nodes of the ASTContext to the locations in the source files.
-It also allows them to analyze information across multiple translation units.</p>
-
-<p>As a "general rule", ASTContexts are considered the primary source of
-information that a client wants about a translation unit. There will be no such class as an
- "indexing database" that stores, for example, source locations of identifiers separately from ASTContext.
-All the information that a client needs from a translation unit will be extracted from the ASTContext.</p>
-
-<h2 id="classes">Classes</h2>
-
-<h3 id="entity">Entity</h3>
-
-<p>To be able to reason about semantically the same Decls that are contained in multiple ASTContexts, the 'Entity' class was introduced.
-An Entity is an ASTContext-independent "token" that can be created from a Decl (and a typename in the future) with
-the purpose to "resolve" it into a Decl belonging to another ASTContext. Some examples to make the concept of Entities more clear:</p>
-
-<p>
-t1.c:
-<pre class="code_example">
-void foo(void);
-void bar(void);
-</pre>
-</p>
-
-<p>
-t2.c:
-<pre class="code_example">
-void foo(void) {
-}
-</pre>
-</p>
-
-<p>
-Translation unit <code>t1.c</code> contains 2 Entities <code>foo</code> and <code>bar</code>, while <code>t2.c</code> contains 1 Entity <code>foo</code>.
-Entities are uniqued in such a way that the Entity* pointer for <code>t1.c/foo</code> is the same as the Entity* pointer for <code>t2.c/foo</code>.
-An Entity doesn't convey any information about the declaration, it is more like an opaque pointer used only to get the
-associated Decl out of an ASTContext so that the actual information for the declaration can be accessed.
-Another important aspect of Entities is that they can only be created/associated for declarations that are visible outside the
-translation unit. This means that for:
-</p>
-<p>
-t3.c:
-<pre class="code_example">
-static void foo(void);
-</pre>
-</p>
-<p>
-there can be no Entity (if you ask for the Entity* of the static function <code>foo</code> you'll get a null pointer).
-This is for 2 reasons:
-<ul>
-<li>To preserve the invariant that the same Entity* pointers refer to the same semantic Decls.
- In the above example <code>t1.c/foo</code> and <code>t2.c/foo</code> are the same, while <code>t3.c/foo</code> is different.</li>
-<li>The purpose of Entity is to get the same semantic Decl from multiple ASTContexts. For a Decl that is not visible
- outside of its own translation unit, you don't need an Entity since it won't appear in another ASTContext.</li>
-</ul>
-</p>
-
-<h3 id="astlocation">ASTLocation</h3>
-
-Encapsulates a "point" in the AST tree of the ASTContext.
-It represents either a Decl*, or a Stmt* along with its immediate Decl* parent.
-An example for its usage is that libIndex will provide the references of <code>foo</code> in the form of ASTLocations,
-"pointing" at the expressions that reference <code>foo</code>.
-
-<h3 id="declreferencemap">DeclReferenceMap</h3>
-
-Accepts an ASTContext and creates a mapping from NamedDecls to the ASTLocations that reference them (in the same ASTContext).
-
-<h2 id="functions">Functions</h2>
-
-<h3 id="resolveloc">ResolveLocationInAST</h3>
-
-A function that accepts an ASTContext and a SourceLocation which it resolves into an ASTLocation.
-
-<h2 id="astfiles">AST Files</h2>
-
-The precompiled headers implementation of clang (<a href="http://clang.llvm.org/docs/PCHInternals.html">PCH</a>) is ideal for storing an ASTContext in a compact form that
-will be loaded later for AST analysis. An "AST file" refers to a translation unit that was "compiled" into a precompiled header file.
-
-<h2 id="indextest">index-test tool</h2>
-
-<h3 id="indextestusage">Usage</h3>
-
-A command-line tool that exercises the libIndex API, useful for testing its features.
-As input it accepts multiple AST files (representing multiple translation units) and a few options:
-
-<p>
-<pre class="code_example">
- -point-at [file:line:column]
-</pre>
-Resolves a [file:line:column] triplet into a ASTLocation from the first AST file. If no other option is specified, it prints the ASTLocation.
-It also prints a declaration's associated doxygen comment, if one is available.
-</p>
-
-<p>
-<pre class="code_example">
- -print-refs
-</pre>
-Prints the ASTLocations that reference the declaration that was resolved out of the [file:line:column] triplet
-</p>
-
-<p>
-<pre class="code_example">
- -print-defs
-</pre>
-Prints the ASTLocations that define the resolved declaration
-</p>
-
-<p>
-<pre class="code_example">
- -print-decls
-</pre>
-Prints the ASTLocations that declare the resolved declaration
-</p>
-
-<h3 id="indextestexamples">Examples</h3>
-
-<p>
-Here's an example of using index-test:
-</p>
-
-<p>
-We have 3 files,
-</p>
-
-<p>
-foo.h:
-<pre class="code_example">
-extern int global_var;
-
-void foo_func(int param1);
-void bar_func(void);
-</pre>
-
-t1.c:
-<pre class="code_example">
-#include "foo.h"
-
-void foo_func(int param1) {
- int local_var = global_var;
- for (int for_var = 100; for_var < 500; ++for_var) {
- local_var = param1 + for_var;
- }
- bar_func();
-}
-</pre>
-
-t2.c:
-<pre class="code_example">
-#include "foo.h"
-
-int global_var = 10;
-
-void bar_func(void) {
- global_var += 100;
- foo_func(global_var);
-}
-</pre>
-</p>
-
-<p>
-You first get AST files out of <code>t1.c</code> and <code>t2.c</code>:
-
-<pre class="code_example">
-$ clang -emit-ast t1.c -o t1.ast
-$ clang -emit-ast t2.c -o t2.ast
-</pre>
-</p>
-
-<p>
-Find the ASTLocation under this position of <code>t1.c</code>:
-<pre class="code_example">
-[...]
-void foo_func(int param1) {
- int local_var = global_var;
- ^
-[...]
-</pre>
-
-<pre class="code_example">
-$ index-test t1.ast -point-at t1.c:4:23
-> [Decl: Var local_var | Stmt: DeclRefExpr global_var] &lt;t1.c:4:19, t1.c:4:19>
-</pre>
-</p>
-
-<p>
-Find the declaration:
-
-<pre class="code_example">
-$ index-test t1.ast -point-at t1.c:4:23 -print-decls
-> [Decl: Var global_var] &lt;foo.h:1:12, foo.h:1:12>
-</pre>
-</p>
-
-<p>
-Find the references:
-
-<pre class="code_example">
-$ index-test t1.ast t2.ast -point-at t1.c:4:23 -print-refs
-> [Decl: Var local_var | Stmt: DeclRefExpr global_var] &lt;t1.c:4:19, t1.c:4:19>
-> [Decl: Function bar_func | Stmt: DeclRefExpr global_var] &lt;t2.c:6:3, t2.c:6:3>
-> [Decl: Function bar_func | Stmt: DeclRefExpr global_var] &lt;t2.c:7:12, t2.c:7:12>
-</pre>
-</p>
-
-<p>
-Find definitions:
-
-<pre class="code_example">
-$ index-test t1.ast t2.ast -point-at t1.c:4:23 -print-defs
-> [Decl: Var global_var] &lt;t2.c:3:5, t2.c:3:18>
-</pre>
-</p>
-
-</div>
-
-</body>
-</html>
diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt
index 8e16ef1..317bc81 100644
--- a/examples/CMakeLists.txt
+++ b/examples/CMakeLists.txt
@@ -1,3 +1,2 @@
add_subdirectory(clang-interpreter)
add_subdirectory(PrintFunctionNames)
-add_subdirectory(Tooling)
diff --git a/examples/Tooling/CMakeLists.txt b/examples/Tooling/CMakeLists.txt
deleted file mode 100644
index 257d3ea..0000000
--- a/examples/Tooling/CMakeLists.txt
+++ /dev/null
@@ -1,6 +0,0 @@
-set(LLVM_USED_LIBS clangTooling clangBasic)
-
-add_clang_executable(clang-check
- ClangCheck.cpp
- )
-
diff --git a/examples/Tooling/ClangCheck.cpp b/examples/Tooling/ClangCheck.cpp
deleted file mode 100644
index 4128375..0000000
--- a/examples/Tooling/ClangCheck.cpp
+++ /dev/null
@@ -1,108 +0,0 @@
-//===- examples/Tooling/ClangCheck.cpp - Clang check tool -----------------===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-//
-// This file implements a clang-check tool that runs the
-// clang::SyntaxOnlyAction over a number of translation units.
-//
-// Usage:
-// clang-check <cmake-output-dir> <file1> <file2> ...
-//
-// Where <cmake-output-dir> is a CMake build directory in which a file named
-// compile_commands.json exists (enable -DCMAKE_EXPORT_COMPILE_COMMANDS in
-// CMake to get this output).
-//
-// <file1> ... specify the paths of files in the CMake source tree. This path
-// is looked up in the compile command database. If the path of a file is
-// absolute, it needs to point into CMake's source tree. If the path is
-// relative, the current working directory needs to be in the CMake source
-// tree and the file must be in a subdirectory of the current working
-// directory. "./" prefixes in the relative files will be automatically
-// removed, but the rest of a relative path must be a suffix of a path in
-// the compile command line database.
-//
-// For example, to use clang-check on all files in a subtree of the source
-// tree, use:
-//
-// /path/in/subtree $ find . -name '*.cpp'| xargs clang-check /path/to/source
-//
-//===----------------------------------------------------------------------===//
-
-#include "clang/Frontend/FrontendActions.h"
-#include "clang/Tooling/Tooling.h"
-#include "llvm/ADT/OwningPtr.h"
-#include "llvm/ADT/Twine.h"
-#include "llvm/Support/MemoryBuffer.h"
-#include "llvm/Support/Path.h"
-#include "llvm/Support/raw_ostream.h"
-#include "llvm/Support/system_error.h"
-
-/// \brief Returns the absolute path of 'File', by prepending it with
-/// 'BaseDirectory' if 'File' is not absolute. Otherwise returns 'File'.
-/// If 'File' starts with "./", the returned path will not contain the "./".
-/// Otherwise, the returned path will contain the literal path-concatenation of
-/// 'BaseDirectory' and 'File'.
-///
-/// \param File Either an absolute or relative path.
-/// \param BaseDirectory An absolute path.
-///
-/// FIXME: Put this somewhere where it is more generally available.
-static std::string GetAbsolutePath(
- llvm::StringRef File, llvm::StringRef BaseDirectory) {
- assert(llvm::sys::path::is_absolute(BaseDirectory));
- if (llvm::sys::path::is_absolute(File)) {
- return File;
- }
- llvm::StringRef RelativePath(File);
- if (RelativePath.startswith("./")) {
- RelativePath = RelativePath.substr(strlen("./"));
- }
- llvm::SmallString<1024> AbsolutePath(BaseDirectory);
- llvm::sys::path::append(AbsolutePath, RelativePath);
- return AbsolutePath.str();
-}
-
-int main(int argc, char **argv) {
- if (argc < 3) {
- llvm::outs() << "Usage: " << argv[0] << " <cmake-output-dir> "
- << "<file1> <file2> ...\n";
- return 1;
- }
- // FIXME: We should pull how to find the database into the Tooling package.
- llvm::OwningPtr<llvm::MemoryBuffer> JsonDatabase;
- llvm::SmallString<1024> JsonDatabasePath(argv[1]);
- llvm::sys::path::append(JsonDatabasePath, "compile_commands.json");
- llvm::error_code Result =
- llvm::MemoryBuffer::getFile(JsonDatabasePath, JsonDatabase);
- if (Result != 0) {
- llvm::outs() << "Error while opening JSON database: " << Result.message()
- << "\n";
- return 1;
- }
- llvm::StringRef BaseDirectory(::getenv("PWD"));
- for (int I = 2; I < argc; ++I) {
- llvm::SmallString<1024> File(GetAbsolutePath(argv[I], BaseDirectory));
- llvm::outs() << "Processing " << File << ".\n";
- std::string ErrorMessage;
- clang::tooling::CompileCommand LookupResult =
- clang::tooling::FindCompileArgsInJsonDatabase(
- File.str(), JsonDatabase->getBuffer(), ErrorMessage);
- if (!LookupResult.CommandLine.empty()) {
- if (!clang::tooling::RunToolWithFlags(
- new clang::SyntaxOnlyAction,
- LookupResult.CommandLine.size(),
- clang::tooling::CommandLineToArgv(
- &LookupResult.CommandLine).data())) {
- llvm::outs() << "Error while processing " << File << ".\n";
- }
- } else {
- llvm::outs() << "Skipping " << File << ". Command line not found.\n";
- }
- }
- return 0;
-}
diff --git a/examples/Tooling/Makefile b/examples/Tooling/Makefile
deleted file mode 100644
index 66e86a0..0000000
--- a/examples/Tooling/Makefile
+++ /dev/null
@@ -1,24 +0,0 @@
-##===- examples/Tooling/Makefile ---------------------------*- Makefile -*-===##
-#
-# The LLVM Compiler Infrastructure
-#
-# This file is distributed under the University of Illinois Open Source
-# License. See LICENSE.TXT for details.
-#
-##===----------------------------------------------------------------------===##
-
-CLANG_LEVEL := ../..
-
-TOOLNAME = clang-check
-NO_INSTALL = 1
-
-# No plugins, optimize startup time.
-TOOL_NO_EXPORTS = 1
-
-LINK_COMPONENTS := support mc
-USEDLIBS = clangFrontend.a clangSerialization.a clangDriver.a \
- clangTooling.a clangSema.a clangAnalysis.a \
- clangAST.a clangParse.a clangLex.a clangBasic.a
-
-include $(CLANG_LEVEL)/Makefile
-
diff --git a/examples/clang-interpreter/Makefile b/examples/clang-interpreter/Makefile
index 3f02003..b565bb1 100644
--- a/examples/clang-interpreter/Makefile
+++ b/examples/clang-interpreter/Makefile
@@ -18,7 +18,8 @@ TOOL_NO_EXPORTS = 1
LINK_COMPONENTS := jit interpreter nativecodegen bitreader bitwriter ipo \
selectiondag asmparser instrumentation
USEDLIBS = clangFrontend.a clangSerialization.a clangDriver.a clangCodeGen.a \
- clangSema.a clangStaticAnalyzerFrontend.a clangStaticAnalyzerCheckers.a clangStaticAnalyzerCore.a clangAnalysis.a clangRewrite.a \
- clangAST.a clangParse.a clangLex.a clangBasic.a
+ clangParse.a clangSema.a clangStaticAnalyzerFrontend.a \
+ clangStaticAnalyzerCheckers.a clangStaticAnalyzerCore.a \
+ clangAnalysis.a clangRewrite.a clangAST.a clangLex.a clangBasic.a
include $(CLANG_LEVEL)/Makefile
diff --git a/examples/clang-interpreter/main.cpp b/examples/clang-interpreter/main.cpp
index ad39ece..16f4dab 100644
--- a/examples/clang-interpreter/main.cpp
+++ b/examples/clang-interpreter/main.cpp
@@ -94,7 +94,7 @@ int main(int argc, const char **argv, char * const *envp) {
// We expect to get back exactly one command job, if we didn't something
// failed. Extract that job from the compilation.
const driver::JobList &Jobs = C->getJobs();
- if (Jobs.size() != 1 || !isa<driver::Command>(Jobs.begin())) {
+ if (Jobs.size() != 1 || !isa<driver::Command>(*Jobs.begin())) {
llvm::SmallString<256> Msg;
llvm::raw_svector_ostream OS(Msg);
C->PrintJob(OS, C->getJobs(), "; ", true);
diff --git a/examples/wpa/Makefile b/examples/wpa/Makefile
index 2ce2040..2cfedbc 100644
--- a/examples/wpa/Makefile
+++ b/examples/wpa/Makefile
@@ -16,8 +16,11 @@ NO_INSTALL = 1
TOOL_NO_EXPORTS = 1
LINK_COMPONENTS := asmparser bitreader mc core
-USEDLIBS = clangStaticAnalyzerFrontend.a clangStaticAnalyzerCheckers.a clangStaticAnalyzerCore.a clangIndex.a clangFrontend.a clangDriver.a \
- clangSema.a clangAnalysis.a clangSerialization.a \
- clangAST.a clangParse.a clangLex.a clangBasic.a
+USEDLIBS = clangStaticAnalyzerFrontend.a \
+ clangStaticAnalyzerCheckers.a \
+ clangStaticAnalyzerCore.a \
+ clangIndex.a clangFrontend.a clangDriver.a \
+ clangParse.a clangSema.a clangAnalysis.a clangSerialization.a \
+ clangAST.a clangLex.a clangBasic.a
include $(CLANG_LEVEL)/Makefile
diff --git a/include/clang-c/Index.h b/include/clang-c/Index.h
index d89a903..cb0b3c1 100644
--- a/include/clang-c/Index.h
+++ b/include/clang-c/Index.h
@@ -222,6 +222,14 @@ CINDEX_LINKAGE CXString clang_getFileName(CXFile SFile);
CINDEX_LINKAGE time_t clang_getFileTime(CXFile SFile);
/**
+ * \brief Determine whether the given header is guarded against
+ * multiple inclusions, either with the conventional
+ * #ifndef/#define/#endif macro guards or with #pragma once.
+ */
+CINDEX_LINKAGE unsigned
+clang_isFileMultipleIncludeGuarded(CXTranslationUnit tu, CXFile file);
+
+/**
* \brief Retrieve a file handle within the given translation unit.
*
* \param tu the translation unit
@@ -821,7 +829,18 @@ enum CXTranslationUnit_Flags {
* Note: this is a *temporary* option that is available only while
* we are testing C++ precompiled preamble support.
*/
- CXTranslationUnit_CXXChainedPCH = 0x20
+ CXTranslationUnit_CXXChainedPCH = 0x20,
+
+ /**
+ * \brief Used to indicate that the "detailed" preprocessing record,
+ * if requested, should also contain nested macro instantiations.
+ *
+ * Nested macro instantiations (i.e., macro instantiations that occur
+ * inside another macro instantiation) can, in some code bases, require
+ * a large amount of storage to due preprocessor metaprogramming. Moreover,
+ * its fairly rare that this information is useful for libclang clients.
+ */
+ CXTranslationUnit_NestedMacroInstantiations = 0x40
};
/**
@@ -1027,12 +1046,14 @@ enum CXTUResourceUsageKind {
CXTUResourceUsage_SourceManager_Membuffer_MMap = 8,
CXTUResourceUsage_ExternalASTSource_Membuffer_Malloc = 9,
CXTUResourceUsage_ExternalASTSource_Membuffer_MMap = 10,
+ CXTUResourceUsage_Preprocessor = 11,
+ CXTUResourceUsage_PreprocessingRecord = 12,
CXTUResourceUsage_MEMORY_IN_BYTES_BEGIN = CXTUResourceUsage_AST,
CXTUResourceUsage_MEMORY_IN_BYTES_END =
- CXTUResourceUsage_ExternalASTSource_Membuffer_MMap,
+ CXTUResourceUsage_PreprocessingRecord,
CXTUResourceUsage_First = CXTUResourceUsage_AST,
- CXTUResourceUsage_Last = CXTUResourceUsage_ExternalASTSource_Membuffer_MMap
+ CXTUResourceUsage_Last = CXTUResourceUsage_PreprocessingRecord
};
/**
@@ -1166,8 +1187,12 @@ enum CXCursorKind {
CXCursor_UsingDeclaration = 35,
/** \brief A C++ alias declaration */
CXCursor_TypeAliasDecl = 36,
+ /** \brief An Objective-C @synthesize definition. */
+ CXCursor_ObjCSynthesizeDecl = 37,
+ /** \brief An Objective-C @dynamic definition. */
+ CXCursor_ObjCDynamicDecl = 38,
CXCursor_FirstDecl = CXCursor_UnexposedDecl,
- CXCursor_LastDecl = CXCursor_TypeAliasDecl,
+ CXCursor_LastDecl = CXCursor_ObjCDynamicDecl,
/* References */
CXCursor_FirstRef = 40, /* Decl references */
@@ -2246,6 +2271,13 @@ CINDEX_LINKAGE CXCursor clang_getCanonicalCursor(CXCursor);
CINDEX_LINKAGE unsigned clang_CXXMethod_isStatic(CXCursor C);
/**
+ * \brief Determine if a C++ member function or member function template is
+ * explicitly declared 'virtual' or if it overrides a virtual method from
+ * one of the base classes.
+ */
+CINDEX_LINKAGE unsigned clang_CXXMethod_isVirtual(CXCursor C);
+
+/**
* \brief Given a cursor that represents a template, determine
* the cursor kind of the specializations would be generated by instantiating
* the template.
diff --git a/include/clang/AST/APValue.h b/include/clang/AST/APValue.h
index 5effa90..fec7d29 100644
--- a/include/clang/AST/APValue.h
+++ b/include/clang/AST/APValue.h
@@ -85,10 +85,10 @@ public:
APValue(const APValue &RHS) : Kind(Uninitialized) {
*this = RHS;
}
- APValue(Expr* B, const CharUnits &O) : Kind(Uninitialized) {
+ APValue(const Expr* B, const CharUnits &O) : Kind(Uninitialized) {
MakeLValue(); setLValue(B, O);
}
- APValue(Expr* B);
+ APValue(const Expr* B);
~APValue() {
MakeUninit();
@@ -167,7 +167,7 @@ public:
return const_cast<APValue*>(this)->getComplexFloatImag();
}
- Expr* getLValueBase() const;
+ const Expr* getLValueBase() const;
CharUnits getLValueOffset() const;
void setInt(const APSInt &I) {
@@ -199,7 +199,7 @@ public:
((ComplexAPFloat*)(char*)Data)->Real = R;
((ComplexAPFloat*)(char*)Data)->Imag = I;
}
- void setLValue(Expr *B, const CharUnits &O);
+ void setLValue(const Expr *B, const CharUnits &O);
const APValue &operator=(const APValue &RHS);
diff --git a/include/clang/AST/ASTContext.h b/include/clang/AST/ASTContext.h
index 28ec8cf..517c25d 100644
--- a/include/clang/AST/ASTContext.h
+++ b/include/clang/AST/ASTContext.h
@@ -406,6 +406,21 @@ public:
/// bitfield which follows the bitfield 'LastFD'.
bool ZeroBitfieldFollowsBitfield(const FieldDecl *FD,
const FieldDecl *LastFD) const;
+
+ /// BitfieldFollowsBitfield - return 'true" if 'FD' is a
+ /// bitfield which follows the bitfield 'LastFD'.
+ bool BitfieldFollowsBitfield(const FieldDecl *FD,
+ const FieldDecl *LastFD) const;
+
+ /// NoneBitfieldFollowsBitfield - return 'true" if 'FD' is not a
+ /// bitfield which follows the bitfield 'LastFD'.
+ bool NoneBitfieldFollowsBitfield(const FieldDecl *FD,
+ const FieldDecl *LastFD) const;
+
+ /// BitfieldFollowsNoneBitfield - return 'true" if 'FD' is a
+ /// bitfield which follows the none bitfield 'LastFD'.
+ bool BitfieldFollowsNoneBitfield(const FieldDecl *FD,
+ const FieldDecl *LastFD) const;
// Access to the set of methods overridden by the given C++ method.
typedef CXXMethodVector::iterator overridden_cxx_method_iterator;
@@ -764,6 +779,10 @@ public:
/// getDecltypeType - C++0x decltype.
QualType getDecltypeType(Expr *e) const;
+ /// getUnaryTransformType - unary type transforms
+ QualType getUnaryTransformType(QualType BaseType, QualType UnderlyingType,
+ UnaryTransformType::UTTKind UKind) const;
+
/// getAutoType - C++0x deduced auto type.
QualType getAutoType(QualType DeducedType) const;
@@ -895,12 +914,18 @@ public:
std::string &S) const;
/// getObjCEncodingForFunctionDecl - Returns the encoded type for this
- //function. This is in the same format as Objective-C method encodings.
- void getObjCEncodingForFunctionDecl(const FunctionDecl *Decl, std::string& S);
+ /// function. This is in the same format as Objective-C method encodings.
+ ///
+ /// \returns true if an error occurred (e.g., because one of the parameter
+ /// types is incomplete), false otherwise.
+ bool getObjCEncodingForFunctionDecl(const FunctionDecl *Decl, std::string& S);
/// getObjCEncodingForMethodDecl - Return the encoded type for this method
/// declaration.
- void getObjCEncodingForMethodDecl(const ObjCMethodDecl *Decl, std::string &S)
+ ///
+ /// \returns true if an error occurred (e.g., because one of the parameter
+ /// types is incomplete), false otherwise.
+ bool getObjCEncodingForMethodDecl(const ObjCMethodDecl *Decl, std::string &S)
const;
/// getObjCEncodingForBlock - Return the encoded type for this block
@@ -1438,7 +1463,8 @@ public:
/// MakeIntValue - Make an APSInt of the appropriate width and
/// signedness for the given \arg Value and integer \arg Type.
llvm::APSInt MakeIntValue(uint64_t Value, QualType Type) const {
- llvm::APSInt Res(getIntWidth(Type), !Type->isSignedIntegerType());
+ llvm::APSInt Res(getIntWidth(Type),
+ !Type->isSignedIntegerOrEnumerationType());
Res = Value;
return Res;
}
@@ -1526,6 +1552,13 @@ public:
/// which declarations were built.
static unsigned NumImplicitCopyConstructorsDeclared;
+ /// \brief The number of implicitly-declared move constructors.
+ static unsigned NumImplicitMoveConstructors;
+
+ /// \brief The number of implicitly-declared move constructors for
+ /// which declarations were built.
+ static unsigned NumImplicitMoveConstructorsDeclared;
+
/// \brief The number of implicitly-declared copy assignment operators.
static unsigned NumImplicitCopyAssignmentOperators;
@@ -1533,6 +1566,13 @@ public:
/// which declarations were built.
static unsigned NumImplicitCopyAssignmentOperatorsDeclared;
+ /// \brief The number of implicitly-declared move assignment operators.
+ static unsigned NumImplicitMoveAssignmentOperators;
+
+ /// \brief The number of implicitly-declared move assignment operators for
+ /// which declarations were built.
+ static unsigned NumImplicitMoveAssignmentOperatorsDeclared;
+
/// \brief The number of implicitly-declared destructors.
static unsigned NumImplicitDestructors;
@@ -1553,7 +1593,13 @@ private:
bool ExpandStructures,
const FieldDecl *Field,
bool OutermostType = false,
- bool EncodingProperty = false) const;
+ bool EncodingProperty = false,
+ bool StructField = false) const;
+
+ // Adds the encoding of the structure's members.
+ void getObjCEncodingForStructureImpl(RecordDecl *RD, std::string &S,
+ const FieldDecl *Field,
+ bool includeVBases = true) const;
const ASTRecordLayout &
getObjCLayout(const ObjCInterfaceDecl *D,
diff --git a/include/clang/AST/CanonicalType.h b/include/clang/AST/CanonicalType.h
index b3550f8..2518814 100644
--- a/include/clang/AST/CanonicalType.h
+++ b/include/clang/AST/CanonicalType.h
@@ -291,6 +291,8 @@ public:
LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isPromotableIntegerType)
LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isSignedIntegerType)
LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isUnsignedIntegerType)
+ LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isSignedIntegerOrEnumerationType)
+ LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isUnsignedIntegerOrEnumerationType)
LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isConstantSizeType)
LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isSpecifierType)
@@ -630,6 +632,14 @@ struct CanProxyAdaptor<DecltypeType> : public CanProxyBase<DecltypeType> {
LLVM_CLANG_CANPROXY_TYPE_ACCESSOR(getUnderlyingType)
};
+template <>
+struct CanProxyAdaptor<UnaryTransformType>
+ : public CanProxyBase<UnaryTransformType> {
+ LLVM_CLANG_CANPROXY_TYPE_ACCESSOR(getBaseType)
+ LLVM_CLANG_CANPROXY_TYPE_ACCESSOR(getUnderlyingType)
+ LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(UnaryTransformType::UTTKind, getUTTKind)
+};
+
template<>
struct CanProxyAdaptor<TagType> : public CanProxyBase<TagType> {
LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(TagDecl *, getDecl)
diff --git a/include/clang/AST/Decl.h b/include/clang/AST/Decl.h
index ef49205..d993d34 100644
--- a/include/clang/AST/Decl.h
+++ b/include/clang/AST/Decl.h
@@ -1365,6 +1365,8 @@ private:
bool HasWrittenPrototype : 1;
bool IsDeleted : 1;
bool IsTrivial : 1; // sunk from CXXMethodDecl
+ bool IsDefaulted : 1; // sunk from CXXMethoDecl
+ bool IsExplicitlyDefaulted : 1; //sunk from CXXMethodDecl
bool HasImplicitReturnZero : 1;
bool IsLateTemplateParsed : 1;
@@ -1448,6 +1450,7 @@ protected:
IsInline(isInlineSpecified), IsInlineSpecified(isInlineSpecified),
IsVirtualAsWritten(false), IsPure(false), HasInheritedPrototype(false),
HasWrittenPrototype(true), IsDeleted(false), IsTrivial(false),
+ IsDefaulted(false), IsExplicitlyDefaulted(false),
HasImplicitReturnZero(false), IsLateTemplateParsed(false),
EndRangeLoc(NameInfo.getEndLoc()),
TemplateOrSpecialization(),
@@ -1512,6 +1515,20 @@ public:
return hasBody(Definition);
}
+ /// hasTrivialBody - Returns whether the function has a trivial body that does
+ /// not require any specific codegen.
+ bool hasTrivialBody() const;
+
+ /// isDefined - Returns true if the function is defined at all, including
+ /// a deleted definition. Except for the behavior when the function is
+ /// deleted, behaves like hasBody.
+ bool isDefined(const FunctionDecl *&Definition) const;
+
+ virtual bool isDefined() const {
+ const FunctionDecl* Definition;
+ return isDefined(Definition);
+ }
+
/// getBody - Retrieve the body (definition) of the function. The
/// function body might be in any of the (re-)declarations of this
/// function. The variant that accepts a FunctionDecl pointer will
@@ -1529,10 +1546,17 @@ public:
/// isThisDeclarationADefinition - Returns whether this specific
/// declaration of the function is also a definition. This does not
/// determine whether the function has been defined (e.g., in a
- /// previous definition); for that information, use getBody.
- /// FIXME: Should return true if function is deleted or defaulted. However,
- /// CodeGenModule.cpp uses it, and I don't know if this would break it.
+ /// previous definition); for that information, use isDefined. Note
+ /// that this returns false for a defaulted function unless that function
+ /// has been implicitly defined (possibly as deleted).
bool isThisDeclarationADefinition() const {
+ return IsDeleted || Body || IsLateTemplateParsed;
+ }
+
+ /// doesThisDeclarationHaveABody - Returns whether this specific
+ /// declaration of the function has a body - that is, if it is a non-
+ /// deleted definition.
+ bool doesThisDeclarationHaveABody() const {
return Body || IsLateTemplateParsed;
}
@@ -1566,6 +1590,16 @@ public:
bool isTrivial() const { return IsTrivial; }
void setTrivial(bool IT) { IsTrivial = IT; }
+ /// Whether this function is defaulted per C++0x. Only valid for
+ /// special member functions.
+ bool isDefaulted() const { return IsDefaulted; }
+ void setDefaulted(bool D = true) { IsDefaulted = D; }
+
+ /// Whether this function is explicitly defaulted per C++0x. Only valid
+ /// for special member functions.
+ bool isExplicitlyDefaulted() const { return IsExplicitlyDefaulted; }
+ void setExplicitlyDefaulted(bool ED = true) { IsExplicitlyDefaulted = ED; }
+
/// Whether falling off this function implicitly returns null/zero.
/// If a more specific implicit return value is required, front-ends
/// should synthesize the appropriate return statements.
@@ -1605,13 +1639,30 @@ public:
/// Integer(long double) = delete; // no construction from long double
/// };
/// @endcode
- bool isDeleted() const { return IsDeleted; }
- void setDeleted(bool D = true) { IsDeleted = D; }
+ // If a function is deleted, its first declaration must be.
+ bool isDeleted() const { return getCanonicalDecl()->IsDeleted; }
+ bool isDeletedAsWritten() const { return IsDeleted && !IsDefaulted; }
+ void setDeletedAsWritten(bool D = true) { IsDeleted = D; }
- /// \brief Determines whether this is a function "main", which is
- /// the entry point into an executable program.
+ /// \brief Determines whether this function is "main", which is the
+ /// entry point into an executable program.
bool isMain() const;
+ /// \brief Determines whether this operator new or delete is one
+ /// of the reserved global placement operators:
+ /// void *operator new(size_t, void *);
+ /// void *operator new[](size_t, void *);
+ /// void operator delete(void *, void *);
+ /// void operator delete[](void *, void *);
+ /// These functions have special behavior under [new.delete.placement]:
+ /// These functions are reserved, a C++ program may not define
+ /// functions that displace the versions in the Standard C++ library.
+ /// The provisions of [basic.stc.dynamic] do not apply to these
+ /// reserved placement forms of operator new and operator delete.
+ ///
+ /// This function must be an allocation or deallocation function.
+ bool isReservedGlobalPlacementOperator() const;
+
/// \brief Determines whether this function is a function with
/// external, C linkage.
bool isExternC() const;
@@ -1902,20 +1953,33 @@ class FieldDecl : public DeclaratorDecl {
bool Mutable : 1;
mutable unsigned CachedFieldIndex : 31;
- Expr *BitWidth;
+ /// \brief A pointer to either the in-class initializer for this field (if
+ /// the boolean value is false), or the bit width expression for this bit
+ /// field (if the boolean value is true).
+ ///
+ /// We can safely combine these two because in-class initializers are not
+ /// permitted for bit-fields.
+ ///
+ /// If the boolean is false and the initializer is null, then this field has
+ /// an in-class initializer which has not yet been parsed and attached.
+ llvm::PointerIntPair<Expr *, 1, bool> InitializerOrBitWidth;
protected:
FieldDecl(Kind DK, DeclContext *DC, SourceLocation StartLoc,
SourceLocation IdLoc, IdentifierInfo *Id,
- QualType T, TypeSourceInfo *TInfo, Expr *BW, bool Mutable)
+ QualType T, TypeSourceInfo *TInfo, Expr *BW, bool Mutable,
+ bool HasInit)
: DeclaratorDecl(DK, DC, IdLoc, Id, T, TInfo, StartLoc),
- Mutable(Mutable), CachedFieldIndex(0), BitWidth(BW) {
+ Mutable(Mutable), CachedFieldIndex(0),
+ InitializerOrBitWidth(BW, !HasInit) {
+ assert(!(BW && HasInit) && "got initializer for bitfield");
}
public:
static FieldDecl *Create(const ASTContext &C, DeclContext *DC,
SourceLocation StartLoc, SourceLocation IdLoc,
IdentifierInfo *Id, QualType T,
- TypeSourceInfo *TInfo, Expr *BW, bool Mutable);
+ TypeSourceInfo *TInfo, Expr *BW, bool Mutable,
+ bool HasInit);
/// getFieldIndex - Returns the index of this field within its record,
/// as appropriate for passing to ASTRecordLayout::getFieldOffset.
@@ -1928,10 +1992,12 @@ public:
void setMutable(bool M) { Mutable = M; }
/// isBitfield - Determines whether this field is a bitfield.
- bool isBitField() const { return BitWidth != NULL; }
+ bool isBitField() const {
+ return InitializerOrBitWidth.getInt() && InitializerOrBitWidth.getPointer();
+ }
/// @brief Determines whether this is an unnamed bitfield.
- bool isUnnamedBitfield() const { return BitWidth != NULL && !getDeclName(); }
+ bool isUnnamedBitfield() const { return isBitField() && !getDeclName(); }
/// isAnonymousStructOrUnion - Determines whether this field is a
/// representative for an anonymous struct or union. Such fields are
@@ -1939,8 +2005,37 @@ public:
/// store the data for the anonymous union or struct.
bool isAnonymousStructOrUnion() const;
- Expr *getBitWidth() const { return BitWidth; }
- void setBitWidth(Expr *BW) { BitWidth = BW; }
+ Expr *getBitWidth() const {
+ return isBitField() ? InitializerOrBitWidth.getPointer() : 0;
+ }
+ void setBitWidth(Expr *BW) {
+ assert(!InitializerOrBitWidth.getPointer() &&
+ "bit width or initializer already set");
+ InitializerOrBitWidth.setPointer(BW);
+ InitializerOrBitWidth.setInt(1);
+ }
+
+ /// hasInClassInitializer - Determine whether this member has a C++0x in-class
+ /// initializer.
+ bool hasInClassInitializer() const {
+ return !InitializerOrBitWidth.getInt();
+ }
+ /// getInClassInitializer - Get the C++0x in-class initializer for this
+ /// member, or null if one has not been set. If a valid declaration has an
+ /// in-class initializer, but this returns null, then we have not parsed and
+ /// attached it yet.
+ Expr *getInClassInitializer() const {
+ return hasInClassInitializer() ? InitializerOrBitWidth.getPointer() : 0;
+ }
+ /// setInClassInitializer - Set the C++0x in-class initializer for this member.
+ void setInClassInitializer(Expr *Init);
+ /// removeInClassInitializer - Remove the C++0x in-class initializer from this
+ /// member.
+ void removeInClassInitializer() {
+ assert(!InitializerOrBitWidth.getInt() && "no initializer to remove");
+ InitializerOrBitWidth.setPointer(0);
+ InitializerOrBitWidth.setInt(1);
+ }
/// getParent - Returns the parent of this field declaration, which
/// is the struct in which this method is defined.
diff --git a/include/clang/AST/DeclBase.h b/include/clang/AST/DeclBase.h
index ce48187..b5047b9 100644
--- a/include/clang/AST/DeclBase.h
+++ b/include/clang/AST/DeclBase.h
@@ -1355,17 +1355,12 @@ struct cast_convert_decl_context<ToTy, true> {
namespace llvm {
/// isa<T>(DeclContext*)
-template<class ToTy>
-struct isa_impl_wrap<ToTy,
- const ::clang::DeclContext,const ::clang::DeclContext> {
+template <typename To>
+struct isa_impl<To, ::clang::DeclContext> {
static bool doit(const ::clang::DeclContext &Val) {
- return ToTy::classofKind(Val.getDeclKind());
+ return To::classofKind(Val.getDeclKind());
}
};
-template<class ToTy>
-struct isa_impl_wrap<ToTy, ::clang::DeclContext, ::clang::DeclContext>
- : public isa_impl_wrap<ToTy,
- const ::clang::DeclContext,const ::clang::DeclContext> {};
/// cast<T>(DeclContext*)
template<class ToTy>
diff --git a/include/clang/AST/DeclCXX.h b/include/clang/AST/DeclCXX.h
index 8c819e3..42a12eb 100644
--- a/include/clang/AST/DeclCXX.h
+++ b/include/clang/AST/DeclCXX.h
@@ -278,10 +278,18 @@ class CXXRecordDecl : public RecordDecl {
/// user-declared copy constructor.
bool UserDeclaredCopyConstructor : 1;
+ /// UserDeclareMoveConstructor - True when this class has a
+ /// user-declared move constructor.
+ bool UserDeclaredMoveConstructor : 1;
+
/// UserDeclaredCopyAssignment - True when this class has a
/// user-declared copy assignment operator.
bool UserDeclaredCopyAssignment : 1;
+ /// UserDeclareMoveAssignment - True when this class has a
+ /// user-declared move assignment.
+ bool UserDeclaredMoveAssignment : 1;
+
/// UserDeclaredDestructor - True when this class has a
/// user-declared destructor.
bool UserDeclaredDestructor : 1;
@@ -337,15 +345,24 @@ class CXXRecordDecl : public RecordDecl {
/// HasPublicFields - True when there are private non-static data members.
bool HasPublicFields : 1;
- /// HasTrivialConstructor - True when this class has a trivial constructor.
+ /// \brief True if this class (or any subobject) has mutable fields.
+ bool HasMutableFields : 1;
+
+ /// HasTrivialDefaultConstructor - True when, if this class has a default
+ /// constructor, this default constructor is trivial.
///
- /// C++ [class.ctor]p5. A constructor is trivial if it is an
- /// implicitly-declared default constructor and if:
- /// * its class has no virtual functions and no virtual base classes, and
- /// * all the direct base classes of its class have trivial constructors, and
- /// * for all the nonstatic data members of its class that are of class type
- /// (or array thereof), each such class has a trivial constructor.
- bool HasTrivialConstructor : 1;
+ /// C++0x [class.ctor]p5
+ /// A default constructor is trivial if it is not user-provided and if
+ /// -- its class has no virtual functions and no virtual base classes,
+ /// and
+ /// -- no non-static data member of its class has a
+ /// brace-or-equal-initializer, and
+ /// -- all the direct base classes of its class have trivial
+ /// default constructors, and
+ /// -- for all the nonstatic data members of its class that are of class
+ /// type (or array thereof), each such class has a trivial
+ /// default constructor.
+ bool HasTrivialDefaultConstructor : 1;
/// HasConstExprNonCopyMoveConstructor - True when this class has at least
/// one constexpr constructor which is neither the copy nor move
@@ -357,7 +374,7 @@ class CXXRecordDecl : public RecordDecl {
///
/// C++0x [class.copy]p13:
/// A copy/move constructor for class X is trivial if it is neither
- /// user-provided nor deleted and if
+ /// user-provided and if
/// -- class X has no virtual functions and no virtual base classes, and
/// -- the constructor selected to copy/move each direct base class
/// subobject is trivial, and
@@ -372,7 +389,7 @@ class CXXRecordDecl : public RecordDecl {
///
/// C++0x [class.copy]p13:
/// A copy/move constructor for class X is trivial if it is neither
- /// user-provided nor deleted and if
+ /// user-provided and if
/// -- class X has no virtual functions and no virtual base classes, and
/// -- the constructor selected to copy/move each direct base class
/// subobject is trivial, and
@@ -430,15 +447,24 @@ class CXXRecordDecl : public RecordDecl {
/// already computed and are available.
bool ComputedVisibleConversions : 1;
- /// \brief Whether we have already declared the default constructor or
- /// do not need to have one declared.
+ /// \brief Whether we have a C++0x user-provided default constructor (not
+ /// explicitly deleted or defaulted).
+ bool UserProvidedDefaultConstructor : 1;
+
+ /// \brief Whether we have already declared the default constructor.
bool DeclaredDefaultConstructor : 1;
/// \brief Whether we have already declared the copy constructor.
bool DeclaredCopyConstructor : 1;
+
+ /// \brief Whether we have already declared the move constructor.
+ bool DeclaredMoveConstructor : 1;
/// \brief Whether we have already declared the copy-assignment operator.
bool DeclaredCopyAssignment : 1;
+
+ /// \brief Whether we have already declared the move-assignment operator.
+ bool DeclaredMoveAssignment : 1;
/// \brief Whether we have already declared a destructor within the class.
bool DeclaredDestructor : 1;
@@ -666,21 +692,30 @@ public:
return data().FirstFriend != 0;
}
- /// \brief Determine whether this class has had its default constructor
- /// declared implicitly or does not need one declared implicitly.
+ /// \brief Determine if we need to declare a default constructor for
+ /// this class.
///
/// This value is used for lazy creation of default constructors.
+ bool needsImplicitDefaultConstructor() const {
+ return !data().UserDeclaredConstructor &&
+ !data().DeclaredDefaultConstructor;
+ }
+
+ /// hasDeclaredDefaultConstructor - Whether this class's default constructor
+ /// has been declared (either explicitly or implicitly).
bool hasDeclaredDefaultConstructor() const {
return data().DeclaredDefaultConstructor;
}
-
+
/// hasConstCopyConstructor - Determines whether this class has a
/// copy constructor that accepts a const-qualified argument.
- bool hasConstCopyConstructor(const ASTContext &Context) const;
+ bool hasConstCopyConstructor() const;
/// getCopyConstructor - Returns the copy constructor for this class
- CXXConstructorDecl *getCopyConstructor(const ASTContext &Context,
- unsigned TypeQuals) const;
+ CXXConstructorDecl *getCopyConstructor(unsigned TypeQuals) const;
+
+ /// getMoveConstructor - Returns the move constructor for this class
+ CXXConstructorDecl *getMoveConstructor() const;
/// \brief Retrieve the copy-assignment operator for this class, if available.
///
@@ -693,6 +728,10 @@ public:
/// \returns The copy-assignment operator that can be invoked, or NULL if
/// a unique copy-assignment operator could not be found.
CXXMethodDecl *getCopyAssignmentOperator(bool ArgIsConst) const;
+
+ /// getMoveAssignmentOperator - Returns the move assignment operator for this
+ /// class
+ CXXMethodDecl *getMoveAssignmentOperator() const;
/// hasUserDeclaredConstructor - Whether this class has any
/// user-declared constructors. When true, a default constructor
@@ -701,6 +740,12 @@ public:
return data().UserDeclaredConstructor;
}
+ /// hasUserProvidedDefaultconstructor - Whether this class has a
+ /// user-provided default constructor per C++0x.
+ bool hasUserProvidedDefaultConstructor() const {
+ return data().UserProvidedDefaultConstructor;
+ }
+
/// hasUserDeclaredCopyConstructor - Whether this class has a
/// user-declared copy constructor. When false, a copy constructor
/// will be implicitly declared.
@@ -715,7 +760,27 @@ public:
bool hasDeclaredCopyConstructor() const {
return data().DeclaredCopyConstructor;
}
-
+
+ /// hasUserDeclaredMoveOperation - Whether this class has a user-
+ /// declared move constructor or assignment operator. When false, a
+ /// move constructor and assignment operator may be implicitly declared.
+ bool hasUserDeclaredMoveOperation() const {
+ return data().UserDeclaredMoveConstructor ||
+ data().UserDeclaredMoveAssignment;
+ }
+
+ /// \brief Determine whether this class has had a move constructor
+ /// declared by the user.
+ bool hasUserDeclaredMoveConstructor() const {
+ return data().UserDeclaredMoveConstructor;
+ }
+
+ /// \brief Determine whether this class has had a move constructor
+ /// declared.
+ bool hasDeclaredMoveConstructor() const {
+ return data().DeclaredMoveConstructor;
+ }
+
/// hasUserDeclaredCopyAssignment - Whether this class has a
/// user-declared copy assignment operator. When false, a copy
/// assigment operator will be implicitly declared.
@@ -730,7 +795,19 @@ public:
bool hasDeclaredCopyAssignment() const {
return data().DeclaredCopyAssignment;
}
-
+
+ /// \brief Determine whether this class has had a move assignment
+ /// declared by the user.
+ bool hasUserDeclaredMoveAssignment() const {
+ return data().UserDeclaredMoveAssignment;
+ }
+
+ /// hasDeclaredMoveAssignment - Whether this class has a
+ /// declared move assignment operator.
+ bool hasDeclaredMoveAssignment() const {
+ return data().DeclaredMoveAssignment;
+ }
+
/// hasUserDeclaredDestructor - Whether this class has a
/// user-declared destructor. When false, a destructor will be
/// implicitly declared.
@@ -800,9 +877,18 @@ public:
/// (C++ [class]p7)
bool isStandardLayout() const { return data().IsStandardLayout; }
- // hasTrivialConstructor - Whether this class has a trivial constructor
- // (C++ [class.ctor]p5)
- bool hasTrivialConstructor() const { return data().HasTrivialConstructor; }
+ /// \brief Whether this class, or any of its class subobjects, contains a
+ /// mutable field.
+ bool hasMutableFields() const { return data().HasMutableFields; }
+
+ // hasTrivialDefaultConstructor - Whether this class has a trivial default
+ // constructor
+ // (C++0x [class.ctor]p5)
+ bool hasTrivialDefaultConstructor() const {
+ return data().HasTrivialDefaultConstructor &&
+ (!data().UserDeclaredConstructor ||
+ data().DeclaredDefaultConstructor);
+ }
// hasConstExprNonCopyMoveConstructor - Whether this class has at least one
// constexpr constructor other than the copy or move constructors
@@ -845,9 +931,18 @@ public:
}
// isTriviallyCopyable - Whether this class is considered trivially copyable
- // (C++0x [class]p5).
+ // (C++0x [class]p6).
bool isTriviallyCopyable() const;
+ // isTrivial - Whether this class is considered trivial
+ //
+ // C++0x [class]p6
+ // A trivial class is a class that has a trivial default constructor and
+ // is trivially copiable.
+ bool isTrivial() const {
+ return isTriviallyCopyable() && hasTrivialDefaultConstructor();
+ }
+
/// \brief If this record is an instantiation of a member class,
/// retrieves the member class from which it was instantiated.
///
@@ -1182,6 +1277,9 @@ public:
/// \brief Determine whether this is a copy-assignment operator, regardless
/// of whether it was declared implicitly or explicitly.
bool isCopyAssignmentOperator() const;
+
+ /// \brief Determine whether this is a move assignment operator.
+ bool isMoveAssignmentOperator() const;
const CXXMethodDecl *getCanonicalDecl() const {
return cast<CXXMethodDecl>(FunctionDecl::getCanonicalDecl());
@@ -1189,6 +1287,12 @@ public:
CXXMethodDecl *getCanonicalDecl() {
return cast<CXXMethodDecl>(FunctionDecl::getCanonicalDecl());
}
+
+ /// isUserProvided - True if it is either an implicit constructor or
+ /// if it was defaulted or deleted on first declaration.
+ bool isUserProvided() const {
+ return !(isDeleted() || getCanonicalDecl()->isDefaulted());
+ }
///
void addOverriddenMethod(const CXXMethodDecl *MD);
@@ -1274,6 +1378,8 @@ class CXXCtorInitializer {
/// \brief The argument used to initialize the base or member, which may
/// end up constructing an object (when multiple arguments are involved).
+ /// If 0, this is a field initializer, and the in-class member initializer
+ /// will be used.
Stmt *Init;
/// LParenLoc - Location of the left paren of the ctor-initializer.
@@ -1348,6 +1454,13 @@ public:
return Initializee.is<IndirectFieldDecl*>();
}
+ /// isInClassMemberInitializer - Returns true when this initializer is an
+ /// implicit ctor initializer generated for a field with an initializer
+ /// defined on the member declaration.
+ bool isInClassMemberInitializer() const {
+ return !Init;
+ }
+
/// isDelegatingInitializer - Returns true when this initializer is creating
/// a delegating constructor.
bool isDelegatingInitializer() const {
@@ -1476,7 +1589,14 @@ public:
reinterpret_cast<VarDecl **>(this + 1)[I] = Index;
}
- Expr *getInit() const { return static_cast<Expr *>(Init); }
+ /// \brief Get the initializer. This is 0 if this is an in-class initializer
+ /// for a non-static data member which has not yet been parsed.
+ Expr *getInit() const {
+ if (!Init)
+ return getAnyMember()->getInClassInitializer();
+
+ return static_cast<Expr*>(Init);
+ }
};
/// CXXConstructorDecl - Represents a C++ constructor within a
@@ -1619,10 +1739,9 @@ public:
/// getTargetConstructor - When this constructor delegates to
/// another, retrieve the target
CXXConstructorDecl *getTargetConstructor() const {
- if (isDelegatingConstructor())
- return CtorInitializers[0]->getTargetConstructor();
- else
- return 0;
+ assert(isDelegatingConstructor() &&
+ "A non-delegating constructor has no target");
+ return CtorInitializers[0]->getTargetConstructor();
}
/// isDefaultConstructor - Whether this constructor is a default
@@ -1693,6 +1812,13 @@ public:
/// \brief Set the constructor that this inheriting constructor is based on.
void setInheritedConstructor(const CXXConstructorDecl *BaseCtor);
+
+ const CXXConstructorDecl *getCanonicalDecl() const {
+ return cast<CXXConstructorDecl>(FunctionDecl::getCanonicalDecl());
+ }
+ CXXConstructorDecl *getCanonicalDecl() {
+ return cast<CXXConstructorDecl>(FunctionDecl::getCanonicalDecl());
+ }
// Implement isa/cast/dyncast/etc.
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
diff --git a/include/clang/AST/DeclObjC.h b/include/clang/AST/DeclObjC.h
index 0a4d864..74ceb43 100644
--- a/include/clang/AST/DeclObjC.h
+++ b/include/clang/AST/DeclObjC.h
@@ -135,6 +135,9 @@ private:
/// in, inout, etc.
unsigned objcDeclQualifier : 6;
+ /// \brief Indicates whether this method has a related result type.
+ unsigned RelatedResultType : 1;
+
// Number of args separated by ':' in a method declaration.
unsigned NumSelectorArgs;
@@ -171,6 +174,7 @@ private:
bool isSynthesized = false,
bool isDefined = false,
ImplementationControl impControl = None,
+ bool HasRelatedResultType = false,
unsigned numSelectorArgs = 0)
: NamedDecl(ObjCMethod, contextDecl, beginLoc, SelInfo),
DeclContext(ObjCMethod), Family(InvalidObjCMethodFamily),
@@ -178,8 +182,8 @@ private:
IsSynthesized(isSynthesized),
IsDefined(isDefined),
DeclImplementation(impControl), objcDeclQualifier(OBJC_TQ_None),
- NumSelectorArgs(numSelectorArgs), MethodDeclType(T),
- ResultTInfo(ResultTInfo),
+ RelatedResultType(HasRelatedResultType), NumSelectorArgs(numSelectorArgs),
+ MethodDeclType(T), ResultTInfo(ResultTInfo),
EndLoc(endLoc), Body(0), SelfDecl(0), CmdDecl(0) {}
/// \brief A definition will return its interface declaration.
@@ -199,6 +203,7 @@ public:
bool isSynthesized = false,
bool isDefined = false,
ImplementationControl impControl = None,
+ bool HasRelatedResultType = false,
unsigned numSelectorArgs = 0);
virtual ObjCMethodDecl *getCanonicalDecl();
@@ -211,6 +216,13 @@ public:
}
void setObjCDeclQualifier(ObjCDeclQualifier QV) { objcDeclQualifier = QV; }
+ /// \brief Determine whether this method has a result type that is related
+ /// to the message receiver's type.
+ bool hasRelatedResultType() const { return RelatedResultType; }
+
+ /// \brief Note whether this method has a related result type.
+ void SetRelatedResultType(bool RRT = true) { RelatedResultType = RRT; }
+
unsigned getNumSelectorArgs() const { return NumSelectorArgs; }
void setNumSelectorArgs(unsigned numSelectorArgs) {
NumSelectorArgs = numSelectorArgs;
@@ -712,7 +724,7 @@ private:
QualType T, TypeSourceInfo *TInfo, AccessControl ac, Expr *BW,
bool synthesized)
: FieldDecl(ObjCIvar, DC, StartLoc, IdLoc, Id, T, TInfo, BW,
- /*Mutable=*/false),
+ /*Mutable=*/false, /*HasInit=*/false),
NextIvar(0), DeclAccess(ac), Synthesized(synthesized) {}
public:
@@ -767,7 +779,7 @@ private:
QualType T, Expr *BW)
: FieldDecl(ObjCAtDefsField, DC, StartLoc, IdLoc, Id, T,
/*TInfo=*/0, // FIXME: Do ObjCAtDefs have declarators ?
- BW, /*Mutable=*/false) {}
+ BW, /*Mutable=*/false, /*HasInit=*/false) {}
public:
static ObjCAtDefsFieldDecl *Create(ASTContext &C, DeclContext *DC,
diff --git a/include/clang/AST/DeclTemplate.h b/include/clang/AST/DeclTemplate.h
index ddbe344..dc50d61 100644
--- a/include/clang/AST/DeclTemplate.h
+++ b/include/clang/AST/DeclTemplate.h
@@ -30,6 +30,7 @@ class ClassTemplatePartialSpecializationDecl;
class TemplateTypeParmDecl;
class NonTypeTemplateParmDecl;
class TemplateTemplateParmDecl;
+class TypeAliasTemplateDecl;
/// \brief Stores a template parameter of any kind.
typedef llvm::PointerUnion3<TemplateTypeParmDecl*, NonTypeTemplateParmDecl*,
@@ -230,6 +231,7 @@ public:
static bool classof(const FunctionTemplateDecl *D) { return true; }
static bool classof(const ClassTemplateDecl *D) { return true; }
static bool classof(const TemplateTemplateParmDecl *D) { return true; }
+ static bool classof(const TypeAliasTemplateDecl *D) { return true; }
static bool classofKind(Kind K) {
return K >= firstTemplate && K <= lastTemplate;
}
@@ -672,6 +674,7 @@ public:
static bool classof(const RedeclarableTemplateDecl *D) { return true; }
static bool classof(const FunctionTemplateDecl *D) { return true; }
static bool classof(const ClassTemplateDecl *D) { return true; }
+ static bool classof(const TypeAliasTemplateDecl *D) { return true; }
static bool classofKind(Kind K) {
return K >= firstRedeclarableTemplate && K <= lastRedeclarableTemplate;
}
@@ -2014,6 +2017,78 @@ public:
friend class ASTDeclReader;
};
+/// Declaration of an alias template. For example:
+///
+/// template <typename T> using V = std::map<T*, int, MyCompare<T>>;
+class TypeAliasTemplateDecl : public RedeclarableTemplateDecl,
+ public RedeclarableTemplate<TypeAliasTemplateDecl> {
+ static void DeallocateCommon(void *Ptr);
+
+protected:
+ typedef RedeclarableTemplate<TypeAliasTemplateDecl> redeclarable_base;
+
+ typedef CommonBase Common;
+
+ TypeAliasTemplateDecl(DeclContext *DC, SourceLocation L, DeclarationName Name,
+ TemplateParameterList *Params, NamedDecl *Decl)
+ : RedeclarableTemplateDecl(TypeAliasTemplate, DC, L, Name, Params, Decl) { }
+
+ CommonBase *newCommon(ASTContext &C);
+
+ Common *getCommonPtr() {
+ return static_cast<Common *>(RedeclarableTemplateDecl::getCommonPtr());
+ }
+
+public:
+ /// Get the underlying function declaration of the template.
+ TypeAliasDecl *getTemplatedDecl() const {
+ return static_cast<TypeAliasDecl*>(TemplatedDecl);
+ }
+
+
+ TypeAliasTemplateDecl *getCanonicalDecl() {
+ return redeclarable_base::getCanonicalDecl();
+ }
+ const TypeAliasTemplateDecl *getCanonicalDecl() const {
+ return redeclarable_base::getCanonicalDecl();
+ }
+
+ /// \brief Retrieve the previous declaration of this function template, or
+ /// NULL if no such declaration exists.
+ TypeAliasTemplateDecl *getPreviousDeclaration() {
+ return redeclarable_base::getPreviousDeclaration();
+ }
+
+ /// \brief Retrieve the previous declaration of this function template, or
+ /// NULL if no such declaration exists.
+ const TypeAliasTemplateDecl *getPreviousDeclaration() const {
+ return redeclarable_base::getPreviousDeclaration();
+ }
+
+ TypeAliasTemplateDecl *getInstantiatedFromMemberTemplate() {
+ return redeclarable_base::getInstantiatedFromMemberTemplate();
+ }
+
+
+ /// \brief Create a function template node.
+ static TypeAliasTemplateDecl *Create(ASTContext &C, DeclContext *DC,
+ SourceLocation L,
+ DeclarationName Name,
+ TemplateParameterList *Params,
+ NamedDecl *Decl);
+
+ /// \brief Create an empty alias template node.
+ static TypeAliasTemplateDecl *Create(ASTContext &C, EmptyShell);
+
+ // Implement isa/cast/dyncast support
+ static bool classof(const Decl *D) { return classofKind(D->getKind()); }
+ static bool classof(const TypeAliasTemplateDecl *D) { return true; }
+ static bool classofKind(Kind K) { return K == TypeAliasTemplate; }
+
+ friend class ASTDeclReader;
+ friend class ASTDeclWriter;
+};
+
/// Implementation of inline functions that require the template declarations
inline AnyFunctionDecl::AnyFunctionDecl(FunctionTemplateDecl *FTD)
: Function(FTD) { }
diff --git a/include/clang/AST/Expr.h b/include/clang/AST/Expr.h
index 5f2d144..ce86458e 100644
--- a/include/clang/AST/Expr.h
+++ b/include/clang/AST/Expr.h
@@ -515,6 +515,14 @@ public:
/// ParenExpr or ImplicitCastExprs, returning their operand.
Expr *IgnoreParenImpCasts();
+ /// IgnoreConversionOperator - Ignore conversion operator. If this Expr is a
+ /// call to a conversion operator, return the argument.
+ Expr *IgnoreConversionOperator();
+
+ const Expr *IgnoreConversionOperator() const {
+ return const_cast<Expr*>(this)->IgnoreConversionOperator();
+ }
+
const Expr *IgnoreParenImpCasts() const {
return const_cast<Expr*>(this)->IgnoreParenImpCasts();
}
@@ -1018,13 +1026,18 @@ public:
false),
Loc(l) {
assert(type->isIntegerType() && "Illegal type in IntegerLiteral");
+ assert(V.getBitWidth() == C.getIntWidth(type) &&
+ "Integer type is not the correct size for constant.");
setValue(C, V);
}
- // type should be IntTy, LongTy, LongLongTy, UnsignedIntTy, UnsignedLongTy,
- // or UnsignedLongLongTy
+ /// \brief Returns a new integer literal with value 'V' and type 'type'.
+ /// \param type - either IntTy, LongTy, LongLongTy, UnsignedIntTy,
+ /// UnsignedLongTy, or UnsignedLongLongTy which should match the size of V
+ /// \param V - the value that the returned integer literal contains.
static IntegerLiteral *Create(ASTContext &C, const llvm::APInt &V,
QualType type, SourceLocation l);
+ /// \brief Returns a new empty integer literal.
static IntegerLiteral *Create(ASTContext &C, EmptyShell Empty);
llvm::APInt getValue() const { return Num.getValue(); }
@@ -1555,9 +1568,9 @@ public:
TSInfo = tsi;
}
- const OffsetOfNode &getComponent(unsigned Idx) {
+ const OffsetOfNode &getComponent(unsigned Idx) const {
assert(Idx < NumComps && "Subscript out of range");
- return reinterpret_cast<OffsetOfNode *> (this + 1)[Idx];
+ return reinterpret_cast<const OffsetOfNode *> (this + 1)[Idx];
}
void setComponent(unsigned Idx, OffsetOfNode ON) {
@@ -1574,6 +1587,9 @@ public:
return reinterpret_cast<Expr **>(
reinterpret_cast<OffsetOfNode *>(this+1) + NumComps)[Idx];
}
+ const Expr *getIndexExpr(unsigned Idx) const {
+ return const_cast<OffsetOfExpr*>(this)->getIndexExpr(Idx);
+ }
void setIndexExpr(unsigned Idx, Expr* E) {
assert(Idx < NumComps && "Subscript out of range");
@@ -3299,6 +3315,9 @@ public:
Expr *getArrayFiller() {
return ArrayFillerOrUnionFieldInit.dyn_cast<Expr *>();
}
+ const Expr *getArrayFiller() const {
+ return const_cast<InitListExpr *>(this)->getArrayFiller();
+ }
void setArrayFiller(Expr *filler);
/// \brief If this initializes a union, specifies which field in the
@@ -3310,6 +3329,9 @@ public:
FieldDecl *getInitializedFieldInUnion() {
return ArrayFillerOrUnionFieldInit.dyn_cast<FieldDecl *>();
}
+ const FieldDecl *getInitializedFieldInUnion() const {
+ return const_cast<InitListExpr *>(this)->getInitializedFieldInUnion();
+ }
void setInitializedFieldInUnion(FieldDecl *FD) {
ArrayFillerOrUnionFieldInit = FD;
}
@@ -4012,6 +4034,42 @@ public:
child_range children() { return child_range(); }
};
+/// AsTypeExpr - Clang builtin function __builtin_astype [OpenCL 6.2.4.2]
+/// This AST node provides support for reinterpreting a type to another
+/// type of the same size.
+class AsTypeExpr : public Expr {
+private:
+ Expr* SrcExpr;
+ QualType DstType;
+ SourceLocation BuiltinLoc, RParenLoc;
+
+public:
+ AsTypeExpr(Expr* SrcExpr, QualType DstType,
+ ExprValueKind VK, ExprObjectKind OK,
+ SourceLocation BuiltinLoc, SourceLocation RParenLoc)
+ : Expr(AsTypeExprClass, DstType, VK, OK, false, false, false),
+ SrcExpr(SrcExpr), DstType(DstType),
+ BuiltinLoc(BuiltinLoc), RParenLoc(RParenLoc) {}
+
+ /// \brief Build an empty __builtin_astype
+ explicit AsTypeExpr(EmptyShell Empty) : Expr(AsTypeExprClass, Empty) {}
+
+ /// getSrcExpr - Return the Expr to be converted.
+ Expr *getSrcExpr() const { return SrcExpr; }
+ QualType getDstType() const { return DstType; }
+
+ SourceRange getSourceRange() const {
+ return SourceRange(BuiltinLoc, RParenLoc);
+ }
+
+ static bool classof(const Stmt *T) {
+ return T->getStmtClass() == AsTypeExprClass;
+ }
+ static bool classof(const AsTypeExpr *) { return true; }
+
+ // Iterators
+ child_range children() { return child_range(); }
+};
} // end namespace clang
#endif
diff --git a/include/clang/AST/ExternalASTSource.h b/include/clang/AST/ExternalASTSource.h
index 6db2336..846813a 100644
--- a/include/clang/AST/ExternalASTSource.h
+++ b/include/clang/AST/ExternalASTSource.h
@@ -211,7 +211,7 @@ public:
return sizes;
}
- virtual void getMemoryBufferSizes(MemoryBufferSizes &sizes) const = 0;
+ virtual void getMemoryBufferSizes(MemoryBufferSizes &sizes) const;
protected:
static DeclContextLookupResult
diff --git a/include/clang/AST/RecursiveASTVisitor.h b/include/clang/AST/RecursiveASTVisitor.h
index 930d193..a8f182a 100644
--- a/include/clang/AST/RecursiveASTVisitor.h
+++ b/include/clang/AST/RecursiveASTVisitor.h
@@ -750,6 +750,11 @@ DEF_TRAVERSE_TYPE(DecltypeType, {
TRY_TO(TraverseStmt(T->getUnderlyingExpr()));
})
+DEF_TRAVERSE_TYPE(UnaryTransformType, {
+ TRY_TO(TraverseType(T->getBaseType()));
+ TRY_TO(TraverseType(T->getUnderlyingType()));
+ })
+
DEF_TRAVERSE_TYPE(AutoType, {
TRY_TO(TraverseType(T->getDeducedType()));
})
@@ -966,6 +971,10 @@ DEF_TRAVERSE_TYPELOC(DecltypeType, {
TRY_TO(TraverseStmt(TL.getTypePtr()->getUnderlyingExpr()));
})
+DEF_TRAVERSE_TYPELOC(UnaryTransformType, {
+ TRY_TO(TraverseTypeLoc(TL.getUnderlyingTInfo()->getTypeLoc()));
+ })
+
DEF_TRAVERSE_TYPELOC(AutoType, {
TRY_TO(TraverseType(TL.getTypePtr()->getDeducedType()));
})
@@ -1368,6 +1377,11 @@ DEF_TRAVERSE_DECL(TypeAliasDecl, {
// source.
})
+DEF_TRAVERSE_DECL(TypeAliasTemplateDecl, {
+ TRY_TO(TraverseDecl(D->getTemplatedDecl()));
+ TRY_TO(TraverseTemplateParameterListHelper(D->getTemplateParameters()));
+ })
+
DEF_TRAVERSE_DECL(UnresolvedUsingTypenameDecl, {
// A dependent using declaration which was marked with 'typename'.
// template<class T> class A : public B<T> { using typename B<T>::foo; };
@@ -1967,6 +1981,9 @@ DEF_TRAVERSE_STMT(FloatingLiteral, { })
DEF_TRAVERSE_STMT(ImaginaryLiteral, { })
DEF_TRAVERSE_STMT(StringLiteral, { })
DEF_TRAVERSE_STMT(ObjCStringLiteral, { })
+
+// Traverse OpenCL: AsType, Convert.
+DEF_TRAVERSE_STMT(AsTypeExpr, { })
// FIXME: look at the following tricky-seeming exprs to see if we
// need to recurse on anything. These are ones that have methods
diff --git a/include/clang/AST/StmtVisitor.h b/include/clang/AST/StmtVisitor.h
index b8c141d..29d2347 100644
--- a/include/clang/AST/StmtVisitor.h
+++ b/include/clang/AST/StmtVisitor.h
@@ -7,7 +7,7 @@
//
//===----------------------------------------------------------------------===//
//
-// This file defines the StmtVisitor interface.
+// This file defines the StmtVisitor and ConstStmtVisitor interfaces.
//
//===----------------------------------------------------------------------===//
@@ -21,20 +21,26 @@
namespace clang {
-#define DISPATCH(NAME, CLASS) \
- return static_cast<ImplClass*>(this)->Visit ## NAME(static_cast<CLASS*>(S))
+template <typename T> struct make_ptr { typedef T *type; };
+template <typename T> struct make_const_ptr { typedef const T *type; };
-/// StmtVisitor - This class implements a simple visitor for Stmt subclasses.
-/// Since Expr derives from Stmt, this also includes support for visiting Exprs.
-template<typename ImplClass, typename RetTy=void>
-class StmtVisitor {
+/// StmtVisitorBase - This class implements a simple visitor for Stmt
+/// subclasses. Since Expr derives from Stmt, this also includes support for
+/// visiting Exprs.
+template<template <typename> class Ptr, typename ImplClass, typename RetTy=void>
+class StmtVisitorBase {
public:
- RetTy Visit(Stmt *S) {
+
+#define PTR(CLASS) typename Ptr<CLASS>::type
+#define DISPATCH(NAME, CLASS) \
+ return static_cast<ImplClass*>(this)->Visit ## NAME(static_cast<PTR(CLASS)>(S))
+
+ RetTy Visit(PTR(Stmt) S) {
// 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)) {
+ if (PTR(BinaryOperator) BinOp = dyn_cast<BinaryOperator>(S)) {
switch (BinOp->getOpcode()) {
default: assert(0 && "Unknown binary operator!");
case BO_PtrMemD: DISPATCH(BinPtrMemD, BinaryOperator);
@@ -72,7 +78,7 @@ public:
case BO_XorAssign: DISPATCH(BinXorAssign, CompoundAssignOperator);
case BO_Comma: DISPATCH(BinComma, BinaryOperator);
}
- } else if (UnaryOperator *UnOp = dyn_cast<UnaryOperator>(S)) {
+ } else if (PTR(UnaryOperator) UnOp = dyn_cast<UnaryOperator>(S)) {
switch (UnOp->getOpcode()) {
default: assert(0 && "Unknown unary operator!");
case UO_PostInc: DISPATCH(UnaryPostInc, UnaryOperator);
@@ -104,13 +110,13 @@ public:
// 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) \
- RetTy Visit ## CLASS(CLASS *S) { DISPATCH(PARENT, PARENT); }
+ RetTy Visit ## CLASS(PTR(CLASS) S) { DISPATCH(PARENT, PARENT); }
#include "clang/AST/StmtNodes.inc"
// If the implementation doesn't implement binary operator methods, fall back
// on VisitBinaryOperator.
#define BINOP_FALLBACK(NAME) \
- RetTy VisitBin ## NAME(BinaryOperator *S) { \
+ RetTy VisitBin ## NAME(PTR(BinaryOperator) S) { \
DISPATCH(BinaryOperator, BinaryOperator); \
}
BINOP_FALLBACK(PtrMemD) BINOP_FALLBACK(PtrMemI)
@@ -130,7 +136,7 @@ public:
// If the implementation doesn't implement compound assignment operator
// methods, fall back on VisitCompoundAssignOperator.
#define CAO_FALLBACK(NAME) \
- RetTy VisitBin ## NAME(CompoundAssignOperator *S) { \
+ RetTy VisitBin ## NAME(PTR(CompoundAssignOperator) S) { \
DISPATCH(CompoundAssignOperator, CompoundAssignOperator); \
}
CAO_FALLBACK(MulAssign) CAO_FALLBACK(DivAssign) CAO_FALLBACK(RemAssign)
@@ -142,7 +148,7 @@ public:
// If the implementation doesn't implement unary operator methods, fall back
// on VisitUnaryOperator.
#define UNARYOP_FALLBACK(NAME) \
- RetTy VisitUnary ## NAME(UnaryOperator *S) { \
+ RetTy VisitUnary ## NAME(PTR(UnaryOperator) S) { \
DISPATCH(UnaryOperator, UnaryOperator); \
}
UNARYOP_FALLBACK(PostInc) UNARYOP_FALLBACK(PostDec)
@@ -156,10 +162,29 @@ public:
#undef UNARYOP_FALLBACK
// Base case, ignore it. :)
- RetTy VisitStmt(Stmt *Node) { return RetTy(); }
-};
+ RetTy VisitStmt(PTR(Stmt) Node) { return RetTy(); }
+#undef PTR
#undef DISPATCH
+};
+
+/// StmtVisitor - This class implements a simple visitor for Stmt subclasses.
+/// Since Expr derives from Stmt, this also includes support for visiting Exprs.
+///
+/// This class does not preserve constness of Stmt pointers (see also
+/// ConstStmtVisitor).
+template<typename ImplClass, typename RetTy=void>
+class StmtVisitor
+ : public StmtVisitorBase<make_ptr, ImplClass, RetTy> {};
+
+/// ConstStmtVisitor - This class implements a simple visitor for Stmt
+/// subclasses. Since Expr derives from Stmt, this also includes support for
+/// visiting Exprs.
+///
+/// This class preserves constness of Stmt pointers (see also StmtVisitor).
+template<typename ImplClass, typename RetTy=void>
+class ConstStmtVisitor
+ : public StmtVisitorBase<make_const_ptr, ImplClass, RetTy> {};
} // end namespace clang
diff --git a/include/clang/AST/Type.h b/include/clang/AST/Type.h
index 975a66f..7763383 100644
--- a/include/clang/AST/Type.h
+++ b/include/clang/AST/Type.h
@@ -294,9 +294,15 @@ public:
/// Generally this answers the question of whether an object with the other
/// qualifiers can be safely used as an object with these qualifiers.
bool compatiblyIncludes(Qualifiers other) const {
- // Non-CVR qualifiers must match exactly. CVR qualifiers may subset.
- return ((Mask & ~CVRMask) == (other.Mask & ~CVRMask)) &&
- (((Mask & CVRMask) | (other.Mask & CVRMask)) == (Mask & CVRMask));
+ return
+ // Address spaces must match exactly.
+ getAddressSpace() == other.getAddressSpace() &&
+ // ObjC GC qualifiers can match, be added, or be removed, but can't be
+ // changed.
+ (getObjCGCAttr() == other.getObjCGCAttr() ||
+ !hasObjCGCAttr() || !other.hasObjCGCAttr()) &&
+ // CVR qualifiers may subset.
+ (((Mask & CVRMask) | (other.Mask & CVRMask)) == (Mask & CVRMask));
}
/// \brief Determine whether this set of qualifiers is a strict superset of
@@ -532,6 +538,14 @@ public:
return withFastQualifiers(Qualifiers::Const);
}
+ /// addVolatile - add the specified type qualifier to this QualType.
+ void addVolatile() {
+ addFastQualifiers(Qualifiers::Volatile);
+ }
+ QualType withVolatile() const {
+ return withFastQualifiers(Qualifiers::Volatile);
+ }
+
void addFastQualifiers(unsigned TQs) {
assert(!(TQs & ~Qualifiers::FastMask)
&& "non-fast qualifier bits set in mask!");
@@ -1183,6 +1197,10 @@ public:
/// (C++0x [basic.types]p9)
bool isTrivialType() const;
+ /// isTriviallyCopyableType - Return true if this is a trivially copyable type
+ /// (C++0x [basic.types]p9
+ bool isTriviallyCopyableType() const;
+
/// \brief Test if this type is a standard-layout type.
/// (C++0x [basic.type]p9)
bool isStandardLayoutType() const;
@@ -1418,16 +1436,22 @@ public:
/// isSignedIntegerType - Return true if this is an integer type that is
/// signed, according to C99 6.2.5p4 [char, signed char, short, int, long..],
- /// an enum decl which has a signed representation, or a vector of signed
- /// integer element type.
+ /// or an enum decl which has a signed representation.
bool isSignedIntegerType() const;
/// isUnsignedIntegerType - Return true if this is an integer type that is
- /// unsigned, according to C99 6.2.5p6 [which returns true for _Bool], an enum
- /// decl which has an unsigned representation, or a vector of unsigned integer
- /// element type.
+ /// unsigned, according to C99 6.2.5p6 [which returns true for _Bool],
+ /// or an enum decl which has an unsigned representation.
bool isUnsignedIntegerType() const;
+ /// Determines whether this is an integer type that is signed or an
+ /// enumeration types whose underlying type is a signed integer type.
+ bool isSignedIntegerOrEnumerationType() const;
+
+ /// Determines whether this is an integer type that is unsigned or an
+ /// enumeration types whose underlying type is a unsigned integer type.
+ bool isUnsignedIntegerOrEnumerationType() const;
+
/// isConstantSizeType - Return true if this is not a variable sized type,
/// according to the rules of C99 6.7.5p3. It is not legal to call this on
/// incomplete types.
@@ -2580,6 +2604,7 @@ public:
}
bool isNothrow(ASTContext &Ctx) const {
ExceptionSpecificationType EST = getExceptionSpecType();
+ assert(EST != EST_Delayed);
if (EST == EST_DynamicNone || EST == EST_BasicNoexcept)
return true;
if (EST != EST_ComputedNoexcept)
@@ -2809,6 +2834,39 @@ public:
Expr *E);
};
+/// \brief A unary type transform, which is a type constructed from another
+class UnaryTransformType : public Type {
+public:
+ enum UTTKind {
+ EnumUnderlyingType
+ };
+
+private:
+ /// The untransformed type.
+ QualType BaseType;
+ /// The transformed type if not dependent, otherwise the same as BaseType.
+ QualType UnderlyingType;
+
+ UTTKind UKind;
+protected:
+ UnaryTransformType(QualType BaseTy, QualType UnderlyingTy, UTTKind UKind,
+ QualType CanonicalTy);
+ friend class ASTContext;
+public:
+ bool isSugared() const { return !isDependentType(); }
+ QualType desugar() const { return UnderlyingType; }
+
+ QualType getUnderlyingType() const { return UnderlyingType; }
+ QualType getBaseType() const { return BaseType; }
+
+ UTTKind getUTTKind() const { return UKind; }
+
+ static bool classof(const Type *T) {
+ return T->getTypeClass() == UnaryTransform;
+ }
+ static bool classof(const UnaryTransformType *) { return true; }
+};
+
class TagType : public Type {
/// Stores the TagDecl associated with this type. The decl may point to any
/// TagDecl that declares the entity.
@@ -3201,6 +3259,10 @@ public:
/// Other template specialization types, for which the template name
/// is dependent, may be canonical types. These types are always
/// dependent.
+///
+/// An instance of this type is followed by an array of TemplateArgument*s,
+/// then, if the template specialization type is for a type alias template,
+/// a QualType representing the non-canonical aliased type.
class TemplateSpecializationType
: public Type, public llvm::FoldingSetNode {
/// \brief The name of the template being specialized.
@@ -3212,7 +3274,8 @@ class TemplateSpecializationType
TemplateSpecializationType(TemplateName T,
const TemplateArgument *Args,
- unsigned NumArgs, QualType Canon);
+ unsigned NumArgs, QualType Canon,
+ QualType Aliased);
friend class ASTContext; // ASTContext creates these
@@ -3247,6 +3310,16 @@ public:
return isa<InjectedClassNameType>(getCanonicalTypeInternal());
}
+ /// True if this template specialization type is for a type alias
+ /// template.
+ bool isTypeAlias() const;
+ /// Get the aliased type, if this is a specialization of a type alias
+ /// template.
+ QualType getAliasedType() const {
+ assert(isTypeAlias() && "not a type alias template specialization");
+ return *reinterpret_cast<const QualType*>(end());
+ }
+
typedef const TemplateArgument * iterator;
iterator begin() const { return getArgs(); }
@@ -3268,12 +3341,14 @@ public:
const TemplateArgument &getArg(unsigned Idx) const; // in TemplateBase.h
bool isSugared() const {
- return !isDependentType() || isCurrentInstantiation();
+ return !isDependentType() || isCurrentInstantiation() || isTypeAlias();
}
QualType desugar() const { return getCanonicalTypeInternal(); }
void Profile(llvm::FoldingSetNodeID &ID, const ASTContext &Ctx) {
Profile(ID, Template, getArgs(), NumArgs, Ctx);
+ if (isTypeAlias())
+ getAliasedType().Profile(ID);
}
static void Profile(llvm::FoldingSetNodeID &ID, TemplateName T,
diff --git a/include/clang/AST/TypeLoc.h b/include/clang/AST/TypeLoc.h
index a1df744..f5669f7 100644
--- a/include/clang/AST/TypeLoc.h
+++ b/include/clang/AST/TypeLoc.h
@@ -1410,6 +1410,53 @@ class DecltypeTypeLoc : public InheritingConcreteTypeLoc<TypeSpecTypeLoc,
DecltypeType> {
};
+struct UnaryTransformTypeLocInfo {
+ // FIXME: While there's only one unary transform right now, future ones may
+ // need different representations
+ SourceLocation KWLoc, LParenLoc, RParenLoc;
+ TypeSourceInfo *UnderlyingTInfo;
+};
+
+class UnaryTransformTypeLoc : public ConcreteTypeLoc<UnqualTypeLoc,
+ UnaryTransformTypeLoc,
+ UnaryTransformType,
+ UnaryTransformTypeLocInfo> {
+public:
+ SourceLocation getKWLoc() const { return getLocalData()->KWLoc; }
+ void setKWLoc(SourceLocation Loc) { getLocalData()->KWLoc = Loc; }
+
+ SourceLocation getLParenLoc() const { return getLocalData()->LParenLoc; }
+ void setLParenLoc(SourceLocation Loc) { getLocalData()->LParenLoc = Loc; }
+
+ SourceLocation getRParenLoc() const { return getLocalData()->RParenLoc; }
+ void setRParenLoc(SourceLocation Loc) { getLocalData()->RParenLoc = Loc; }
+
+ TypeSourceInfo* getUnderlyingTInfo() const {
+ return getLocalData()->UnderlyingTInfo;
+ }
+ void setUnderlyingTInfo(TypeSourceInfo *TInfo) {
+ getLocalData()->UnderlyingTInfo = TInfo;
+ }
+
+ SourceRange getLocalSourceRange() const {
+ return SourceRange(getKWLoc(), getRParenLoc());
+ }
+
+ SourceRange getParensRange() const {
+ return SourceRange(getLParenLoc(), getRParenLoc());
+ }
+ void setParensRange(SourceRange Range) {
+ setLParenLoc(Range.getBegin());
+ setRParenLoc(Range.getEnd());
+ }
+
+ void initializeLocal(ASTContext &Context, SourceLocation Loc) {
+ setKWLoc(Loc);
+ setRParenLoc(Loc);
+ setLParenLoc(Loc);
+ }
+};
+
class AutoTypeLoc : public InheritingConcreteTypeLoc<TypeSpecTypeLoc,
AutoTypeLoc,
AutoType> {
diff --git a/include/clang/AST/TypeNodes.def b/include/clang/AST/TypeNodes.def
index b2591cc..0792d0d 100644
--- a/include/clang/AST/TypeNodes.def
+++ b/include/clang/AST/TypeNodes.def
@@ -84,6 +84,7 @@ NON_CANONICAL_TYPE(Typedef, Type)
NON_CANONICAL_UNLESS_DEPENDENT_TYPE(TypeOfExpr, Type)
NON_CANONICAL_UNLESS_DEPENDENT_TYPE(TypeOf, Type)
NON_CANONICAL_UNLESS_DEPENDENT_TYPE(Decltype, Type)
+NON_CANONICAL_UNLESS_DEPENDENT_TYPE(UnaryTransform, Type)
ABSTRACT_TYPE(Tag, Type)
TYPE(Record, TagType)
TYPE(Enum, TagType)
diff --git a/include/clang/Basic/BuiltinsARM.def b/include/clang/Basic/BuiltinsARM.def
index 080d17f..888e529 100644
--- a/include/clang/Basic/BuiltinsARM.def
+++ b/include/clang/Basic/BuiltinsARM.def
@@ -24,12 +24,26 @@ BUILTIN(__builtin_arm_qsub, "iii", "nc")
BUILTIN(__builtin_arm_ssat, "iiUi", "nc")
BUILTIN(__builtin_arm_usat, "UiUiUi", "nc")
+// Store and load exclusive doubleword
+BUILTIN(__builtin_arm_ldrexd, "LLUiv*", "")
+BUILTIN(__builtin_arm_strexd, "iLLUiv*", "")
+
// VFP
BUILTIN(__builtin_arm_get_fpscr, "Ui", "nc")
BUILTIN(__builtin_arm_set_fpscr, "vUi", "nc")
BUILTIN(__builtin_arm_vcvtr_f, "ffi", "nc")
BUILTIN(__builtin_arm_vcvtr_d, "fdi", "nc")
+// Coprocessor
+BUILTIN(__builtin_arm_mcr, "vUiUiUiUiUiUi", "")
+BUILTIN(__builtin_arm_mcr2, "vUiUiUiUiUiUi", "")
+BUILTIN(__builtin_arm_mrc, "UiUiUiUiUiUi", "")
+BUILTIN(__builtin_arm_mrc2, "UiUiUiUiUiUi", "")
+BUILTIN(__builtin_arm_cdp, "vUiUiUiUiUiUi", "")
+BUILTIN(__builtin_arm_cdp2, "vUiUiUiUiUiUi", "")
+BUILTIN(__builtin_arm_mcrr, "vUiUiUiUiUi", "")
+BUILTIN(__builtin_arm_mcrr2, "vUiUiUiUiUi", "")
+
// NEON
#define GET_NEON_BUILTINS
#include "clang/Basic/arm_neon.inc"
diff --git a/include/clang/Basic/BuiltinsX86.def b/include/clang/Basic/BuiltinsX86.def
index 2c2a84a..6ef667d 100644
--- a/include/clang/Basic/BuiltinsX86.def
+++ b/include/clang/Basic/BuiltinsX86.def
@@ -278,7 +278,6 @@ BUILTIN(__builtin_ia32_cvttps2dq, "V4iV4f", "")
BUILTIN(__builtin_ia32_clflush, "vvC*", "")
BUILTIN(__builtin_ia32_lfence, "v", "")
BUILTIN(__builtin_ia32_mfence, "v", "")
-BUILTIN(__builtin_ia32_loaddqu, "V16ccC*", "")
BUILTIN(__builtin_ia32_storedqu, "vc*V16c", "")
BUILTIN(__builtin_ia32_pmuludq128, "V2LLiV4iV4i", "")
BUILTIN(__builtin_ia32_psraw128, "V8sV8sV8s", "")
diff --git a/include/clang/Basic/DeclNodes.td b/include/clang/Basic/DeclNodes.td
index 9e69492..ddd0827 100644
--- a/include/clang/Basic/DeclNodes.td
+++ b/include/clang/Basic/DeclNodes.td
@@ -50,6 +50,7 @@ def Named : Decl<1>;
def RedeclarableTemplate : DDecl<Template, 1>;
def FunctionTemplate : DDecl<RedeclarableTemplate>;
def ClassTemplate : DDecl<RedeclarableTemplate>;
+ def TypeAliasTemplate : DDecl<RedeclarableTemplate>;
def TemplateTemplateParm : DDecl<Template>;
def Using : DDecl<Named>;
def UsingShadow : DDecl<Named>;
diff --git a/include/clang/Basic/Diagnostic.h b/include/clang/Basic/Diagnostic.h
index 7fc400f..fa76324 100644
--- a/include/clang/Basic/Diagnostic.h
+++ b/include/clang/Basic/Diagnostic.h
@@ -32,6 +32,7 @@ namespace clang {
class LangOptions;
class Preprocessor;
class DiagnosticErrorTrap;
+ class StoredDiagnostic;
/// \brief Annotates a diagnostic with some code that should be
/// inserted, removed, or replaced to fix the problem.
@@ -400,6 +401,7 @@ public:
void setExtensionHandlingBehavior(ExtensionHandling H) {
ExtBehavior = H;
}
+ ExtensionHandling getExtensionHandlingBehavior() const { return ExtBehavior; }
/// AllExtensionsSilenced - This is a counter bumped when an __extension__
/// block is encountered. When non-zero, all extension diagnostics are
@@ -423,7 +425,7 @@ public:
///
/// 'Loc' is the source location that this change of diagnostic state should
/// take affect. It can be null if we are setting the state from command-line.
- bool setDiagnosticGroupMapping(const char *Group, diag::Mapping Map,
+ bool setDiagnosticGroupMapping(llvm::StringRef Group, diag::Mapping Map,
SourceLocation Loc = SourceLocation()) {
return Diags->setDiagnosticGroupMapping(Group, Map, Loc, *this);
}
@@ -487,6 +489,8 @@ public:
inline DiagnosticBuilder Report(SourceLocation Pos, unsigned DiagID);
inline DiagnosticBuilder Report(unsigned DiagID);
+ void Report(const StoredDiagnostic &storedDiag);
+
/// \brief Determine whethere there is already a diagnostic in flight.
bool isDiagnosticInFlight() const { return CurDiagID != ~0U; }
@@ -839,8 +843,11 @@ inline DiagnosticBuilder Diagnostic::Report(unsigned DiagID) {
/// about the currently in-flight diagnostic.
class DiagnosticInfo {
const Diagnostic *DiagObj;
+ llvm::StringRef StoredDiagMessage;
public:
explicit DiagnosticInfo(const Diagnostic *DO) : DiagObj(DO) {}
+ DiagnosticInfo(const Diagnostic *DO, llvm::StringRef storedDiagMessage)
+ : DiagObj(DO), StoredDiagMessage(storedDiagMessage) {}
const Diagnostic *getDiags() const { return DiagObj; }
unsigned getID() const { return DiagObj->CurDiagID; }
diff --git a/include/clang/Basic/DiagnosticCommonKinds.td b/include/clang/Basic/DiagnosticCommonKinds.td
index 0b0bca0..50110fb 100644
--- a/include/clang/Basic/DiagnosticCommonKinds.td
+++ b/include/clang/Basic/DiagnosticCommonKinds.td
@@ -52,6 +52,12 @@ def err_invalid_storage_class_in_func_decl : Error<
def err_expected_namespace_name : Error<"expected namespace name">;
def ext_variadic_templates : ExtWarn<
"variadic templates are a C++0x extension">, InGroup<CXX0x>;
+def err_default_special_members : Error<
+ "only special member functions may be defaulted">;
+def err_friends_define_only_namespace_scope : Error<
+ "cannot define a function with non-namespace scope in a friend declaration">;
+def err_deleted_non_function : Error<
+ "only functions can have deleted definitions">;
// Sema && Lex
def ext_longlong : Extension<
diff --git a/include/clang/Basic/DiagnosticFrontendKinds.td b/include/clang/Basic/DiagnosticFrontendKinds.td
index 67fc22e..4aa8513 100644
--- a/include/clang/Basic/DiagnosticFrontendKinds.td
+++ b/include/clang/Basic/DiagnosticFrontendKinds.td
@@ -281,6 +281,9 @@ def err_not_a_pch_file : Error<
def warn_unknown_warning_option : Warning<
"unknown warning option '%0'">,
InGroup<DiagGroup<"unknown-warning-option"> >;
+def warn_unknown_negative_warning_option : Warning<
+ "unknown warning option '%0'">,
+ InGroup<DiagGroup<"unknown-warning-option"> >, DefaultIgnore;
def warn_unknown_warning_specifier : Warning<
"unknown %0 warning specifier: '%1'">,
InGroup<DiagGroup<"unknown-warning-option"> >;
diff --git a/include/clang/Basic/DiagnosticGroups.td b/include/clang/Basic/DiagnosticGroups.td
index c85acc5..9abd6d3 100644
--- a/include/clang/Basic/DiagnosticGroups.td
+++ b/include/clang/Basic/DiagnosticGroups.td
@@ -33,8 +33,11 @@ def : DiagGroup<"char-align">;
def Comment : DiagGroup<"comment">;
def : DiagGroup<"ctor-dtor-privacy">;
def : DiagGroup<"declaration-after-statement">;
+def DefaultArgSpecialMember : DiagGroup<"default-arg-special-member">;
def GNUDesignator : DiagGroup<"gnu-designator">;
+def DeleteNonVirtualDtor : DiagGroup<"delete-non-virtual-dtor">;
+
def DeprecatedDeclarations : DiagGroup<"deprecated-declarations">;
def DeprecatedWritableStr : DiagGroup<"deprecated-writable-strings">;
def Deprecated : DiagGroup<"deprecated", [ DeprecatedDeclarations] >,
@@ -144,7 +147,7 @@ def : DiagGroup<"type-limits">;
def Uninitialized : DiagGroup<"uninitialized">;
def UninitializedMaybe : DiagGroup<"conditional-uninitialized">;
def UnknownPragmas : DiagGroup<"unknown-pragmas">;
-def UnknownAttributes : DiagGroup<"unknown-attributes">;
+def UnknownAttributes : DiagGroup<"attributes">;
def UnnamedTypeTemplateArgs : DiagGroup<"unnamed-type-template-args">;
def UnusedArgument : DiagGroup<"unused-argument">;
def UnusedExceptionParameter : DiagGroup<"unused-exception-parameter">;
@@ -235,6 +238,7 @@ def Extra : DiagGroup<"extra", [
def Most : DiagGroup<"most", [
CharSubscript,
Comment,
+ DeleteNonVirtualDtor,
Format,
Implicit,
MismatchedTags,
@@ -271,6 +275,8 @@ def NonGCC : DiagGroup<"non-gcc",
def CXX0xStaticNonIntegralInitializer :
DiagGroup<"c++0x-static-nonintegral-init">;
def CXX0x : DiagGroup<"c++0x-extensions", [CXX0xStaticNonIntegralInitializer]>;
+def DelegatingCtorCycles :
+ DiagGroup<"delegating-ctor-cycles">;
// A warning group for warnings about GCC extensions.
def GNU : DiagGroup<"gnu", [GNUDesignator, VLA]>;
diff --git a/include/clang/Basic/DiagnosticIDs.h b/include/clang/Basic/DiagnosticIDs.h
index 0296b96..fa816de 100644
--- a/include/clang/Basic/DiagnosticIDs.h
+++ b/include/clang/Basic/DiagnosticIDs.h
@@ -101,7 +101,7 @@ public:
/// getDescription - Given a diagnostic ID, return a description of the
/// issue.
- const char *getDescription(unsigned DiagID) const;
+ llvm::StringRef getDescription(unsigned DiagID) const;
/// isBuiltinWarningOrExtension - Return true if the unmapped diagnostic
/// level of the specified diagnostic ID is a Warning or Extension.
@@ -132,15 +132,18 @@ public:
/// getWarningOptionForDiag - Return the lowest-level warning option that
/// enables the specified diagnostic. If there is no -Wfoo flag that controls
/// the diagnostic, this returns null.
- static const char *getWarningOptionForDiag(unsigned DiagID);
-
+ static llvm::StringRef getWarningOptionForDiag(unsigned DiagID);
+
/// getCategoryNumberForDiag - Return the category number that a specified
/// DiagID belongs to, or 0 if no category.
static unsigned getCategoryNumberForDiag(unsigned DiagID);
+ /// getNumberOfCategories - Return the number of categories
+ static unsigned getNumberOfCategories();
+
/// getCategoryNameFromID - Given a category ID, return the name of the
/// category.
- static const char *getCategoryNameFromID(unsigned CategoryID);
+ static llvm::StringRef getCategoryNameFromID(unsigned CategoryID);
/// \brief Enumeration describing how the the emission of a diagnostic should
/// be treated when it occurs during C++ template argument deduction.
@@ -179,24 +182,24 @@ public:
static SFINAEResponse getDiagnosticSFINAEResponse(unsigned DiagID);
/// getName - Given a diagnostic ID, return its name
- static const char *getName(unsigned DiagID);
+ static llvm::StringRef getName(unsigned DiagID);
/// getIdFromName - Given a diagnostic name, return its ID, or 0
- static unsigned getIdFromName(char const *Name);
+ static unsigned getIdFromName(llvm::StringRef Name);
/// getBriefExplanation - Given a diagnostic ID, return a brief explanation
/// of the issue
- static const char *getBriefExplanation(unsigned DiagID);
+ static llvm::StringRef getBriefExplanation(unsigned DiagID);
/// getFullExplanation - Given a diagnostic ID, return a full explanation
/// of the issue
- static const char *getFullExplanation(unsigned DiagID);
+ static llvm::StringRef getFullExplanation(unsigned DiagID);
private:
/// setDiagnosticGroupMapping - Change an entire diagnostic group (e.g.
/// "unknown-pragmas" to have the specified mapping. This returns true and
/// ignores the request if "Group" was unknown, false otherwise.
- bool setDiagnosticGroupMapping(const char *Group, diag::Mapping Map,
+ bool setDiagnosticGroupMapping(llvm::StringRef Group, diag::Mapping Map,
SourceLocation Loc, Diagnostic &Diag) const;
/// \brief Based on the way the client configured the Diagnostic
diff --git a/include/clang/Basic/DiagnosticParseKinds.td b/include/clang/Basic/DiagnosticParseKinds.td
index c37e510..fb1c909 100644
--- a/include/clang/Basic/DiagnosticParseKinds.td
+++ b/include/clang/Basic/DiagnosticParseKinds.td
@@ -108,6 +108,7 @@ def err_expected_ident_lparen : Error<"expected identifier or '('">;
def err_expected_ident_lbrace : Error<"expected identifier or '{'">;
def err_expected_lbrace : Error<"expected '{'">;
def err_expected_lparen : Error<"expected '('">;
+def err_expected_lparen_or_lbrace : Error<"expected '('or '{'">;
def err_expected_rparen : Error<"expected ')'">;
def err_expected_lsquare : Error<"expected '['">;
def err_expected_rsquare : Error<"expected ']'">;
@@ -161,6 +162,8 @@ def err_unexpected_namespace_attributes_alias : Error<
def err_inline_namespace_alias : Error<"namespace alias cannot be inline">;
def err_namespace_nonnamespace_scope : Error<
"namespaces can only be defined in global or namespace scope">;
+def err_nested_namespaces_with_double_colon : Error<
+ "nested namespace definition must define each namespace separately">;
def err_expected_semi_after_attribute_list : Error<
"expected ';' after attribute list">;
def err_expected_semi_after_static_assert : Error<
@@ -190,6 +193,8 @@ def ext_ref_qualifier : ExtWarn<
"reference qualifiers on functions are a C++0x extension">, InGroup<CXX0x>;
def ext_inline_namespace : ExtWarn<
"inline namespaces are a C++0x feature">, InGroup<CXX0x>;
+def err_generalized_initializer_lists : Error<
+ "generalized initializer lists are a C++0x extension unsupported in Clang">;
def ext_generalized_initializer_lists : ExtWarn<
"generalized initializer lists are a C++0x extension unsupported in Clang">,
InGroup<CXX0x>;
@@ -343,6 +348,9 @@ def err_operator_string_not_empty : Error<
// Classes.
def err_anon_type_definition : Error<
"declaration of anonymous %0 must be a definition">;
+def err_default_delete_in_multiple_declaration : Error<
+ "'= %select{default|delete}0' is a function definition and must occur in a "
+ "standalone declaration">;
def err_cxx0x_attribute_forbids_arguments : Error<
"C++0x attribute '%0' cannot have an argument list">;
@@ -434,12 +442,26 @@ def err_missing_whitespace_digraph : Error<
def warn_deleted_function_accepted_as_extension: ExtWarn<
"deleted function definition accepted as a C++0x extension">, InGroup<CXX0x>;
+def warn_defaulted_function_accepted_as_extension: ExtWarn<
+ "defaulted function definition accepted as a C++0x extension">,
+ InGroup<CXX0x>;
+
+// C++0x in-class member initialization
+def warn_nonstatic_member_init_accepted_as_extension: ExtWarn<
+ "in-class initialization of non-static data member accepted as a C++0x extension">,
+ InGroup<CXX0x>;
+def err_bitfield_member_init: Error<
+ "bitfield member cannot have an in-class initializer">;
+def err_incomplete_array_member_init: Error<
+ "array bound cannot be deduced from an in-class initializer">;
// C++0x alias-declaration
def ext_alias_declaration : ExtWarn<
"alias declarations accepted as a C++0x extension">, InGroup<CXX0x>;
def err_alias_declaration_not_identifier : Error<
"name defined in alias declaration must be an identifier">;
+def err_alias_declaration_specialization : Error<
+ "%select{partial specialization|explicit specialization|explicit instantiation}0 of alias templates is not permitted">;
// C++0x override control
def ext_override_control_keyword : Extension<
diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td
index 0a0c91a..5cfa61b 100644
--- a/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/include/clang/Basic/DiagnosticSemaKinds.td
@@ -261,10 +261,11 @@ def err_builtin_definition : Error<"definition of builtin function %0">;
def err_types_compatible_p_in_cplusplus : Error<
"__builtin_types_compatible_p is not valid in C++">;
def warn_builtin_unknown : Warning<"use of unknown builtin %0">, DefaultError;
-def warn_non_pod_memset : Warning<
- "destination for this memset call is a pointer to a non-POD type %0">,
- InGroup<DiagGroup<"non-pod-memset">>, DefaultIgnore;
-def note_non_pod_memset_silence : Note<
+def warn_dyn_class_memaccess : Warning<
+ "%select{destination for|source of}0 this %1 call is a pointer to dynamic "
+ "class %2; vtable pointer will be overwritten">,
+ InGroup<DiagGroup<"dynamic-class-memaccess">>;
+def note_bad_memaccess_silence : Note<
"explicitly cast the pointer to silence this warning">;
/// main()
@@ -371,7 +372,8 @@ def warn_conflicting_ret_types : Warning<
"conflicting return type in implementation of %0: %1 vs %2">;
def warn_conflicting_ret_type_modifiers : Warning<
"conflicting distributed object modifiers on return type "
- "in implementation of %0">;
+ "in implementation of %0">,
+ InGroup<DiagGroup<"distributed-object-modifiers">>;
def warn_non_covariant_ret_types : Warning<
"conflicting return type in implementation of %0: %1 vs %2">,
InGroup<DiagGroup<"method-signatures">>, DefaultIgnore;
@@ -380,7 +382,8 @@ def warn_conflicting_param_types : Warning<
"conflicting parameter types in implementation of %0: %1 vs %2">;
def warn_conflicting_param_modifiers : Warning<
"conflicting distributed object modifiers on parameter type "
- "in implementation of %0">;
+ "in implementation of %0">,
+ InGroup<DiagGroup<"distributed-object-modifiers">>;
def warn_non_contravariant_param_types : Warning<
"conflicting parameter types in implementation of %0: %1 vs %2">,
InGroup<DiagGroup<"method-signatures">>, DefaultIgnore;
@@ -495,6 +498,8 @@ def err_static_assert_expression_is_not_constant : Error<
"static_assert expression is not an integral constant expression">;
def err_static_assert_failed : Error<"static_assert failed \"%0\"">;
+def warn_inline_namespace_reopened_noninline : Warning<
+ "inline namespace cannot be re-opened as a non-inline namespace">;
def err_inline_namespace_mismatch : Error<
"%select{|non-}0inline namespace "
"cannot be reopened as %select{non-|}0inline">;
@@ -504,11 +509,12 @@ def err_unexpected_friend : Error<
def ext_enum_friend : ExtWarn<
"enumeration type %0 cannot be a friend">;
def ext_nonclass_type_friend : ExtWarn<
- "non-class type %0 cannot be a friend">;
+ "non-class friend type %0 is a C++0x extension">, InGroup<CXX0x>;
def err_friend_is_member : Error<
"friends cannot be members of the declaring class">;
def ext_unelaborated_friend_type : ExtWarn<
- "must specify '%select{struct|union|class|enum}0' to befriend %1">;
+ "specify '%select{struct|union|class|enum}0' to befriend %1; accepted "
+ "as a C++0x extension">, InGroup<CXX0x>;
def err_qualified_friend_not_found : Error<
"no function named %0 with type %1 was found in the specified scope">;
def err_introducing_special_friend : Error<
@@ -539,12 +545,12 @@ def err_type_defined_in_result_type : Error<
"%0 can not be defined in the result type of a function">;
def err_type_defined_in_param_type : Error<
"%0 can not be defined in a parameter type">;
+def err_type_defined_in_alias_template : Error<
+ "%0 can not be defined in a type alias template">;
def note_pure_virtual_function : Note<
"unimplemented pure virtual method %0 in %1">;
-def err_deleted_non_function : Error<
- "only functions can have deleted definitions">;
def err_deleted_decl_not_first : Error<
"deleted definition must be first declaration">;
@@ -572,6 +578,9 @@ def warn_mismatched_exception_spec : ExtWarn<
def err_override_exception_spec : Error<
"exception specification of overriding function is more lax than "
"base version">;
+def warn_override_exception_spec : ExtWarn<
+ "exception specification of overriding function is more lax than "
+ "base version">, InGroup<Microsoft>;
def err_incompatible_exception_specs : Error<
"target exception specification is not superset of source">;
def err_deep_exception_specs_differ : Error<
@@ -580,12 +589,18 @@ def warn_missing_exception_specification : Warning<
"%0 is missing exception specification '%1'">;
def err_noexcept_needs_constant_expression : Error<
"argument to noexcept specifier must be a constant expression">;
+def err_exception_spec_unknown : Error<
+ "exception specification is not available until end of class definition">;
// C++ access checking
def err_class_redeclared_with_different_access : Error<
"%0 redeclared with '%1' access">;
def err_access : Error<
"%1 is a %select{private|protected}0 member of %3">, AccessControl;
+def war_ms_using_declaration_inaccessible : ExtWarn<
+ "using declaration refers to inaccessible member '%0', which refers "
+ "to accessible member '%1', accepted for Microsoft compatibility">,
+ AccessControl, InGroup<Microsoft>;
def err_access_ctor : Error<
"calling a %select{private|protected}0 constructor of class %2">,
AccessControl;
@@ -593,13 +608,18 @@ def ext_rvalue_to_reference_access_ctor : ExtWarn<
"C++98 requires an accessible copy constructor for class %2 when binding "
"a reference to a temporary; was %select{private|protected}0">,
AccessControl, InGroup<BindToTemporaryCopy>;
-def err_access_base : Error<
+def err_access_base_ctor : Error<
+ // The ERRORs represent other special members that aren't constructors, in
+ // hopes that someone will bother noticing and reporting if they appear
"%select{base class|inherited virtual base class}0 %1 has %select{private|"
- "protected}3 %select{constructor|copy constructor|copy assignment operator|"
- "destructor}2">, AccessControl;
-def err_access_field: Error<
- "field of type %0 has %select{private|protected}2 %select{constructor|copy "
- "constructor|copy assignment operator|destructor}1">, AccessControl;
+ "protected}3 %select{default |copy |move |*ERROR* |*ERROR* "
+ "|*ERROR*|}2constructor">, AccessControl;
+def err_access_field_ctor : Error<
+ // The ERRORs represent other special members that aren't constructors, in
+ // hopes that someone will bother noticing and reporting if they appear
+ "field of type %0 has %select{private|protected}2 "
+ "%select{default |copy |move |*ERROR* |*ERROR* |*ERROR* |}1constructor">,
+ AccessControl;
def err_access_ctor_field :
Error<"field of type %1 has %select{private|protected}2 constructor">,
@@ -715,39 +735,52 @@ def err_member_function_initialization : Error<
"initializer on function does not look like a pure-specifier">;
def err_non_virtual_pure : Error<
"%0 is not virtual and cannot be declared pure">;
+def warn_pure_function_definition : ExtWarn<
+ "function definition with pure-specifier is a Microsoft extension">,
+ InGroup<Microsoft>;
def err_implicit_object_parameter_init : Error<
"cannot initialize object parameter of type %0 with an expression "
"of type %1">;
def err_qualified_member_of_unrelated : Error<
"%q0 is not a member of class %1">;
+def warn_call_to_pure_virtual_member_function_from_ctor_dtor : Warning<
+ "call to pure virtual member function %0; overrides of %0 in subclasses are "
+ "not available in the %select{constructor|destructor}1 of %2">;
+
def note_field_decl : Note<"member is declared here">;
def note_ivar_decl : Note<"ivar is declared here">;
def note_bitfield_decl : Note<"bit-field is declared here">;
def note_previous_decl : Note<"%0 declared here">;
def note_member_synthesized_at : Note<
- "implicit default %select{constructor|copy constructor|"
- "copy assignment operator|destructor}0 for %1 first required here">;
+ "implicit default %select{constructor|copy constructor|move constructor|copy "
+ "assignment operator|move assignment operator|destructor}0 for %1 first "
+ "required here">;
def err_missing_default_ctor : Error<
"%select{|implicit default }0constructor for %1 must explicitly initialize "
"the %select{base class|member}2 %3 which does not have a default "
"constructor">;
def err_illegal_union_or_anon_struct_member : Error<
"%select{anonymous struct|union}0 member %1 has a non-trivial "
- "%select{constructor|copy constructor|copy assignment operator|destructor}2">;
+ "%select{constructor|copy constructor|move constructor|copy assignment "
+ "operator|move assignment operator|destructor}2">;
def note_nontrivial_has_virtual : Note<
"because type %0 has a virtual %select{member function|base class}1">;
def note_nontrivial_has_nontrivial : Note<
"because type %0 has a %select{member|base class}1 with a non-trivial "
- "%select{constructor|copy constructor|copy assignment operator|destructor}2">;
+ "%select{constructor|copy constructor|move constructor|copy assignment "
+ "operator|move assignment operator|destructor}2">;
def note_nontrivial_user_defined : Note<
"because type %0 has a user-declared %select{constructor|copy constructor|"
- "copy assignment operator|destructor}1">;
+ "move constructor|copy assignment operator|move assignment operator|"
+ "destructor}1">;
def err_static_data_member_not_allowed_in_union_or_anon_struct : Error<
"static data member %0 not allowed in %select{anonymous struct|union}1">;
def err_union_member_of_reference_type : Error<
"union member %0 has reference type %1">;
-
+def ext_anonymous_struct_union_qualified : Extension<
+ "anonymous %select{struct|union}0 cannot be '%select{const|volatile|"
+ "restrict}1'">;
def err_different_return_type_for_overriding_virtual_function : Error<
"virtual function %0 has a different return type (%1) than the "
"function it overrides (which has return type %2)">;
@@ -942,8 +975,8 @@ def err_illegal_decl_array_of_auto : Error<
def err_new_array_of_auto : Error<
"cannot allocate array of 'auto'">;
def err_auto_not_allowed : Error<
- "'auto' not allowed %select{in function prototype|in struct member"
- "|in union member|in class member|in exception declaration"
+ "'auto' not allowed %select{in function prototype|in non-static struct member"
+ "|in non-static union member|in non-static class member|in exception declaration"
"|in template parameter|in block literal|in template argument"
"|in typedef|in type alias|in function return type|here}0">;
def err_auto_var_requires_init : Error<
@@ -1000,16 +1033,23 @@ def err_enum_redeclare_fixed_mismatch : Error<
"enumeration previously declared with %select{non|}0fixed underlying type">;
def err_enum_redeclare_scoped_mismatch : Error<
"enumeration previously declared as %select{un|}0scoped">;
+def err_only_enums_have_underlying_types : Error<
+ "only enumeration types have underlying types">;
+def err_incomplete_type_no_underlying_type : Error<
+ "an incomplete enumeration type has no underlying type yet">;
// C++0x delegating constructors
def err_delegation_0x_only : Error<
"delegating constructors are permitted only in C++0x">;
-def err_delegation_unimplemented : Error<
- "delegating constructors are not fully implemented">;
def err_delegating_initializer_alone : Error<
"an initializer for a delegating constructor must appear alone">;
-def err_delegating_ctor_loop : Error<
- "constructor %0 delegates to itself (possibly indirectly)">;
+def warn_delegating_ctor_cycle : Warning<
+ "constructor for %0 creates a delegation cycle">, DefaultError,
+ InGroup<DelegatingCtorCycles>;
+def note_it_delegates_to : Note<
+ "it delegates to">, InGroup<DelegatingCtorCycles>;
+def note_which_delegates_to : Note<
+ "which delegates to">, InGroup<DelegatingCtorCycles>;
def err_delegating_codegen_not_implemented : Error<
"code generation for delegating constructors not implemented">;
@@ -1140,6 +1180,8 @@ def warn_attribute_void_function_method : Warning<
"%select{functions|Objective-C method}1 without return value">;
def warn_attribute_weak_on_field : Warning<
"__weak attribute cannot be specified on a field declaration">;
+def warn_gc_attribute_weak_on_local : Warning<
+ "Objective-C GC does not allow weak variables on the stack">;
def warn_attribute_weak_on_local : Warning<
"__weak attribute cannot be specified on an automatic variable">;
def warn_weak_identifier_undeclared : Warning<
@@ -1242,7 +1284,9 @@ def warn_impcast_different_enum_types : Warning<
def warn_impcast_bool_to_null_pointer : Warning<
"initialization of pointer of type %0 to NULL from a constant boolean "
"expression">, InGroup<BoolConversions>;
-
+def warn_impcast_null_pointer_to_integer : Warning<
+ "implicit conversion of NULL constant to integer">,
+ InGroup<DiagGroup<"conversion">>, DefaultIgnore;
def warn_cast_align : Warning<
"cast from %0 to %1 increases required alignment from %2 to %3">,
@@ -1374,6 +1418,13 @@ def note_first_required_here : Note<
def err_uninitialized_member_in_ctor : Error<
"%select{|implicit default }0constructor for %1 must explicitly initialize "
"the %select{reference|const}2 member %3">;
+def warn_default_arg_makes_ctor_special : Warning<
+ "addition of default argument on redeclaration makes this constructor a "
+ "%select{default|copy|move}0 constructor">, InGroup<DefaultArgSpecialMember>;
+def note_previous_declaration_special : Note<
+ // The ERRORs are in hopes that if they occur, they'll get reported.
+ "previous declaration was %select{*ERROR*|a copy constructor|a move "
+ "constructor|*ERROR*|*ERROR*|*ERROR*|not a special member function}0">;
def err_use_of_default_argument_to_function_declared_later : Error<
"use of default argument to function %0 that is declared later in class %1">;
@@ -1412,7 +1463,9 @@ def note_ovl_candidate : Note<"candidate "
"function |function |constructor |"
"is the implicit default constructor|"
"is the implicit copy constructor|"
+ "is the implicit move constructor|"
"is the implicit copy assignment operator|"
+ "is the implicit move assignment operator|"
"is an inherited constructor}0%1">;
def note_ovl_candidate_inherited_constructor : Note<"inherited from here">;
@@ -1443,7 +1496,9 @@ def note_ovl_candidate_arity : Note<"candidate "
"%select{function|function|constructor|function|function|constructor|"
"constructor (the implicit default constructor)|"
"constructor (the implicit copy constructor)|"
+ "constructor (the implicit move constructor)|"
"function (the implicit copy assignment operator)|"
+ "function (the implicit move assignment operator)|"
"constructor (inherited)}0 %select{|template }1"
"not viable: requires%select{ at least| at most|}2 %3 argument%s3, but %4 "
"%plural{1:was|:were}4 provided">;
@@ -1463,7 +1518,9 @@ def note_ovl_candidate_bad_conv_incomplete : Note<"candidate "
"function |function |constructor |"
"constructor (the implicit default constructor)|"
"constructor (the implicit copy constructor)|"
+ "constructor (the implicit move constructor)|"
"function (the implicit copy assignment operator)|"
+ "function (the implicit move assignment operator)|"
"constructor (inherited)}0%1 "
"not viable: cannot convert argument of incomplete type %2 to %3">;
def note_ovl_candidate_bad_overload : Note<"candidate "
@@ -1471,7 +1528,9 @@ def note_ovl_candidate_bad_overload : Note<"candidate "
"function |function |constructor |"
"constructor (the implicit default constructor)|"
"constructor (the implicit copy constructor)|"
+ "constructor (the implicit move constructor)|"
"function (the implicit copy assignment operator)|"
+ "function (the implicit move assignment operator)|"
"constructor (inherited)}0%1"
" not viable: no overload of %3 matching %2 for %ordinal4 argument">;
def note_ovl_candidate_bad_conv : Note<"candidate "
@@ -1479,7 +1538,9 @@ def note_ovl_candidate_bad_conv : Note<"candidate "
"function |function |constructor |"
"constructor (the implicit default constructor)|"
"constructor (the implicit copy constructor)|"
+ "constructor (the implicit move constructor)|"
"function (the implicit copy assignment operator)|"
+ "function (the implicit move assignment operator)|"
"constructor (inherited)}0%1"
" not viable: no known conversion from %2 to %3 for "
"%select{%ordinal5 argument|object argument}4">;
@@ -1488,7 +1549,9 @@ def note_ovl_candidate_bad_addrspace : Note<"candidate "
"function |function |constructor |"
"constructor (the implicit default constructor)|"
"constructor (the implicit copy constructor)|"
+ "constructor (the implicit move constructor)|"
"function (the implicit copy assignment operator)|"
+ "function (the implicit move assignment operator)|"
"constructor (inherited)}0%1 not viable: "
"%select{%ordinal6|'this'}5 argument (%2) is in "
"address space %3, but parameter must be in address space %4">;
@@ -1497,7 +1560,9 @@ def note_ovl_candidate_bad_gc : Note<"candidate "
"function |function |constructor |"
"constructor (the implicit default constructor)|"
"constructor (the implicit copy constructor)|"
+ "constructor (the implicit move constructor)|"
"function (the implicit copy assignment operator)|"
+ "function (the implicit move assignment operator)|"
"constructor (inherited)}0%1 not viable: "
"%select{%ordinal6|'this'}5 argument (%2) has %select{no|__weak|__strong}3 "
"lifetime, but parameter has %select{no|__weak|__strong}4 lifetime">;
@@ -1512,7 +1577,9 @@ def note_ovl_candidate_bad_cvr : Note<"candidate "
"function |function |constructor |"
"constructor (the implicit default constructor)|"
"constructor (the implicit copy constructor)|"
+ "constructor (the implicit move constructor)|"
"function (the implicit copy assignment operator)|"
+ "function (the implicit move assignment operator)|"
"constructor (inherited)}0%1 not viable: "
"%ordinal4 argument (%2) would lose "
"%select{const|restrict|const and restrict|volatile|const and volatile|"
@@ -1523,7 +1590,9 @@ def note_ovl_candidate_bad_base_to_derived_conv : Note<"candidate "
"function |function |constructor |"
"constructor (the implicit default constructor)|"
"constructor (the implicit copy constructor)|"
+ "constructor (the implicit move constructor)|"
"function (the implicit copy assignment operator)|"
+ "function (the implicit move assignment operator)|"
"constructor (inherited)}0%1"
" not viable: cannot %select{convert from|convert from|bind}2 "
"%select{base class pointer|superclass|base class object of type}2 %3 to "
@@ -1666,7 +1735,7 @@ def err_template_arg_must_be_expr : Error<
def err_template_arg_nontype_ambig : Error<
"template argument for non-type template parameter is treated as type %0">;
def err_template_arg_must_be_template : Error<
- "template argument for template template parameter must be a class template">;
+ "template argument for template template parameter must be a class template%select{| or type alias template}0">;
def ext_template_arg_local_type : ExtWarn<
"template argument uses local type %0">, InGroup<LocalTypeTemplateArgs>;
def ext_template_arg_unnamed_type : ExtWarn<
@@ -1802,6 +1871,8 @@ def err_not_class_template_specialization : Error<
"parameter}0">;
def err_function_specialization_in_class : Error<
"cannot specialize a function %0 within class scope">;
+def err_explicit_specialization_storage_class : Error<
+ "explicit specialization cannot have a storage class">;
// C++ class template specializations and out-of-line definitions
def err_template_spec_needs_header : Error<
@@ -1812,6 +1883,8 @@ def err_template_spec_needs_template_parameters : Error<
def err_template_param_list_matches_nontemplate : Error<
"template parameter list matching the non-templated nested type %0 should "
"be empty ('template<>')">;
+def err_alias_template_extra_headers : Error<
+ "extraneous template parameter list in alias template declaration">;
def err_template_spec_extra_headers : Error<
"extraneous template parameter list in template specialization or "
"out-of-line template definition">;
@@ -1823,6 +1896,9 @@ def note_explicit_template_spec_does_not_need_header : Note<
def err_template_qualified_declarator_no_match : Error<
"nested name specifier '%0' for declaration does not refer into a class, "
"class template or class template partial specialization">;
+def err_specialize_member_of_template : Error<
+ "cannot specialize (with 'template<>') a member of an unspecialized "
+ "template">;
// C++ Class Template Partial Specialization
def err_default_arg_in_partial_spec : Error<
@@ -1889,6 +1965,8 @@ def note_function_template_spec_here : Note<
"in instantiation of function template specialization %q0 requested here">;
def note_template_static_data_member_def_here : Note<
"in instantiation of static data member %q0 requested here">;
+def note_template_type_alias_instantiation_here : Note<
+ "in instantiation of template type alias %0 requested here">;
def note_default_arg_instantiation_here : Note<
"in instantiation of default argument for '%0' required here">;
@@ -1954,6 +2032,8 @@ def err_explicit_instantiation_requires_name : Error<
"explicit instantiation declaration requires a name">;
def err_explicit_instantiation_of_typedef : Error<
"explicit instantiation of typedef %0">;
+def err_explicit_instantiation_storage_class : Error<
+ "explicit instantiation cannot have a storage class">;
def err_explicit_instantiation_not_known : Error<
"explicit instantiation of %0 does not refer to a function template, member "
"function, member class, or static data member">;
@@ -1971,7 +2051,7 @@ def note_explicit_instantiation_candidate : Note<
"explicit instantiation candidate function template here %0">;
def err_explicit_instantiation_inline : Error<
"explicit instantiation cannot be 'inline'">;
-def ext_explicit_instantiation_without_qualified_id : ExtWarn<
+def ext_explicit_instantiation_without_qualified_id : Extension<
"qualifier in explicit instantiation of %q0 requires a template-id "
"(a typedef is not permitted)">;
def err_explicit_instantiation_unqualified_wrong_namespace : Error<
@@ -2026,7 +2106,7 @@ def err_non_type_template_in_nested_name_specifier : Error<
def err_template_id_not_a_type : Error<
"template name refers to non-type template '%0'">;
def note_template_declared_here : Note<
- "%select{function template|class template|template template parameter}0 "
+ "%select{function template|class template|type alias template|template template parameter}0 "
"%1 declared here">;
// C++0x Variadic Templates
@@ -2099,6 +2179,10 @@ def err_unexpected_namespace : Error<
def err_undeclared_var_use : Error<"use of undeclared identifier %0">;
def note_dependent_var_use : Note<"must qualify identifier to find this "
"declaration in dependent base class">;
+def err_not_found_by_two_phase_lookup : Error<"call to function %0 that is neither "
+ "visible in the template definition nor found by argument dependent lookup">;
+def note_not_found_by_two_phase_lookup : Note<"%0 should be declared prior to the "
+ "call site%select{| or in %2| or in an associated namespace of one of its arguments}1">;
def err_undeclared_use : Error<"use of undeclared %0">;
def warn_deprecated : Warning<"%0 is deprecated">,
InGroup<DeprecatedDeclarations>;
@@ -2115,7 +2199,8 @@ def err_unavailable_message : Error<"%0 is unavailable: %1">;
def warn_unavailable_fwdclass_message : Warning<
"%0 maybe unavailable because receiver type is unknown">;
def note_unavailable_here : Note<
- "function has been explicitly marked %select{unavailable|deleted|deprecated}0 here">;
+ "function has been explicitly marked "
+ "%select{unavailable|deleted|deprecated}0 here">;
def warn_not_enough_argument : Warning<
"not enough variable arguments in %0 declaration to fit a sentinel">;
def warn_missing_sentinel : Warning <
@@ -2127,8 +2212,13 @@ def warn_missing_prototype : Warning<
InGroup<DiagGroup<"missing-prototypes">>, DefaultIgnore;
def err_redefinition : Error<"redefinition of %0">;
def err_definition_of_implicitly_declared_member : Error<
- "definition of implicitly declared %select{constructor|copy constructor|"
- "copy assignment operator|destructor}1">;
+ "definition of implicitly declared %select{default constructor|copy "
+ "constructor|move constructor|copy assignment operator|move assignment "
+ "operator|destructor}1">;
+def err_definition_of_explicitly_defaulted_member : Error<
+ "definition of explicitly defaulted %select{default constructor|copy "
+ "constructor|move constructor|copy assignment operator|move assignment "
+ "operator|destructor}0">;
def err_redefinition_extern_inline : Error<
"redefinition of a 'extern inline' function %0 is not supported in "
"%select{C99 mode|C++}1">;
@@ -2164,9 +2254,9 @@ def err_redefinition_different_type : Error<
def err_redefinition_different_kind : Error<
"redefinition of %0 as different kind of symbol">;
def err_redefinition_different_typedef : Error<
- "%select{typedef|type alias}0 redefinition with different types (%1 vs %2)">;
+ "%select{typedef|type alias|type alias template}0 redefinition with different types (%1 vs %2)">;
def err_tag_reference_non_tag : Error<
- "elaborated type refers to %select{a non-tag type|a typedef|a type alias|a template}0">;
+ "elaborated type refers to %select{a non-tag type|a typedef|a type alias|a template|a type alias template}0">;
def err_tag_reference_conflict : Error<
"implicit declaration introduced by elaborated type conflicts with "
"%select{a declaration|a typedef|a type alias|a template}0 of the same name">;
@@ -2180,9 +2270,15 @@ def err_nested_redefinition : Error<"nested redefinition of %0">;
def err_use_with_wrong_tag : Error<
"use of %0 with tag type that does not match previous declaration">;
def warn_struct_class_tag_mismatch : Warning<
- "%select{struct|class}0 %select{|template}1 %2 was previously declared "
- "as a %select{class|struct}0 %select{|template}1">,
+ "%select{struct|class}0%select{| template}1 %2 was previously declared "
+ "as a %select{class|struct}0%select{| template}1">,
InGroup<MismatchedTags>, DefaultIgnore;
+def warn_struct_class_previous_tag_mismatch : Warning<
+ "%2 defined as a %select{struct|class}0%select{| template}1 here but "
+ "previously declared as a %select{class|struct}0%select{| template}1">,
+ InGroup<MismatchedTags>, DefaultIgnore;
+def note_struct_class_suggestion : Note<
+ "did you mean %select{struct|class}0 here?">;
def ext_forward_ref_enum : Extension<
"ISO C forbids forward references to 'enum' types">;
def err_forward_ref_enum : Error<
@@ -2482,6 +2578,14 @@ def note_precedence_bitwise_first : Note<
def note_precedence_bitwise_silence : Note<
"place parentheses around the %0 expression to silence this warning">;
+def warn_precedence_conditional : Warning<
+ "?: has lower precedence than %0; %0 will be evaluated first">,
+ InGroup<Parentheses>;
+def note_precedence_conditional_first : Note<
+ "place parentheses around the ?: expression to evaluate it first">;
+def note_precedence_conditional_silence : Note<
+ "place parentheses around the %0 expression to silence this warning">;
+
def warn_logical_instead_of_bitwise : Warning<
"use of logical %0 with constant operand; switch to bitwise %1 or "
"remove constant">, InGroup<DiagGroup<"constant-logical-operand">>;
@@ -2641,6 +2745,10 @@ def warn_indirection_through_null : Warning<
"indirection of non-volatile null pointer will be deleted, not trap">, InGroup<NullDereference>;
def note_indirection_through_null : Note<
"consider using __builtin_trap() or qualifying pointer with 'volatile'">;
+def warn_pointer_indirection_from_incompatible_type : Warning<
+ "dereference of type %1 that was reinterpret_cast from type %0 has undefined "
+ "behavior.">,
+ InGroup<DiagGroup<"undefined-reinterpret-cast">>, DefaultIgnore;
def err_assignment_requires_nonfragile_object : Error<
"cannot assign to class object in non-fragile ABI (%0 invalid)">;
@@ -2839,6 +2947,8 @@ def err_objc_pointer_cxx_catch_fragile : Error<
"exception model">;
def err_objc_object_catch : Error<
"can't catch an Objective C object by value">;
+def err_incomplete_type_objc_at_encode : Error<
+ "'@encode' of incomplete type %0">;
def warn_setter_getter_impl_required : Warning<
"property %0 requires method %1 to be defined - "
@@ -2904,6 +3014,9 @@ def err_bad_cxx_cast_member_pointer_size : Error<
def err_bad_static_cast_incomplete : Error<"%0 is an incomplete type">;
def err_bad_reinterpret_cast_reference : Error<
"reinterpret_cast of a %0 to %1 needs its address which is not allowed">;
+def warn_undefined_reinterpret_cast : Warning<
+ "reinterpret_cast from %0 to %1 has undefined behavior.">,
+ InGroup<DiagGroup<"undefined-reinterpret-cast">>, DefaultIgnore;
// These messages don't adhere to the pattern.
// FIXME: Display the path somehow better.
@@ -3016,6 +3129,9 @@ def err_objc_exceptions_disabled : Error<
def warn_non_virtual_dtor : Warning<
"%0 has virtual functions but non-virtual destructor">,
InGroup<NonVirtualDtor>, DefaultIgnore;
+def warn_delete_non_virtual_dtor : Warning<
+ "delete called on %0 that has virtual functions but non-virtual destructor">,
+ InGroup<DeleteNonVirtualDtor>, DefaultIgnore;
def warn_overloaded_virtual : Warning<
"%q0 hides overloaded virtual %select{function|functions}1">,
InGroup<OverloadedVirtual>, DefaultIgnore;
@@ -3170,7 +3286,8 @@ def ext_typecheck_convert_incompatible_pointer : ExtWarn<
"%select{assigning to|passing|returning|converting|initializing|sending|casting}2"
" %0 "
"%select{from|to parameter of type|from a function with result type|to type|"
- "with an expression of type|to parameter of type|to type}2 %1">;
+ "with an expression of type|to parameter of type|to type}2 %1">,
+ InGroup<DiagGroup<"incompatible-pointer-types">>;
def ext_typecheck_convert_discards_qualifiers : ExtWarn<
"%select{assigning to|passing|returning|converting|initializing|sending|casting}2"
" %0 "
@@ -3281,8 +3398,8 @@ def err_cannot_pass_objc_interface_to_vararg : Error<
"%select{function|block|method}1">;
def warn_cannot_pass_non_pod_arg_to_vararg : Warning<
- "cannot pass object of non-POD type %0 through variadic "
- "%select{function|block|method|constructor}1; call will abort at runtime">,
+ "cannot pass object of %select{non-POD|non-trivial}0 type %1 through variadic"
+ " %select{function|block|method|constructor}2; call will abort at runtime">,
InGroup<DiagGroup<"non-pod-varargs">>, DefaultError;
def err_typecheck_call_invalid_ordered_compare : Error<
@@ -3591,6 +3708,47 @@ def warn_not_compound_assign : Warning<
def warn_explicit_conversion_functions : Warning<
"explicit conversion functions are a C++0x extension">, InGroup<CXX0x>;
+// C++0x defaulted functions
+def err_defaulted_default_ctor_params : Error<
+ "an explicitly-defaulted default constructor must have no parameters">;
+def err_defaulted_copy_ctor_params : Error<
+ "an explicitly-defaulted copy constructor must have exactly one parameter">;
+def err_defaulted_copy_ctor_volatile_param : Error<
+ "the parameter for an explicitly-defaulted copy constructor may not be "
+ "volatile">;
+def err_defaulted_copy_ctor_const_param : Error<
+ "the parameter for this explicitly-defaulted copy constructor is const, but "
+ "a member or base requires it to be non-const">;
+def err_defaulted_copy_assign_params : Error<
+ "an explicitly-defaulted copy assignment operator must have exactly one "
+ "parameter">;
+def err_defaulted_copy_assign_return_type : Error<
+ "an explicitly-defaulted copy assignment operator must return an unqualified "
+ "lvalue reference to its class type">;
+def err_defaulted_copy_assign_not_ref : Error<
+ "the parameter for an explicitly-defaulted copy assignment operator must be an "
+ "lvalue reference type">;
+def err_defaulted_copy_assign_volatile_param : Error<
+ "the parameter for an explicitly-defaulted copy assignment operator may not "
+ "be volatile">;
+def err_defaulted_copy_assign_const_param : Error<
+ "the parameter for this explicitly-defaulted copy assignment operator is "
+ "const, but a member or base requires it to be non-const">;
+def err_defaulted_copy_assign_quals : Error<
+ "an explicitly-defaulted copy assignment operator may not have 'const' "
+ "or 'volatile' qualifiers">;
+def err_incorrect_defaulted_exception_spec : Error<
+ "exception specification of explicitly defaulted %select{default constructor|"
+ "copy constructor|move constructor|copy assignment operator|move assignment "
+ "operator|destructor}0 does not match the "
+ "calculated one">;
+def err_out_of_line_default_deletes : Error<
+ "defaulting this %select{default constructor|copy constructor|move "
+ "constructor|copy assignment operator|move assignment operator|destructor}0 "
+ "would delete it after its first declaration">;
+def err_defaulted_move_unsupported : Error<
+ "defaulting move functions not yet supported">;
+
def warn_array_index_precedes_bounds : Warning<
"array index of '%0' indexes before the beginning of the array">,
InGroup<DiagGroup<"array-bounds">>;
@@ -3955,7 +4113,28 @@ def err_unknown_any_var_function_type : Error<
def err_filter_expression_integral : Error<
"filter expression type should be an integral value not %0">;
+// OpenCL warnings and errors.
+def err_invalid_astype_of_different_size : Error<
+ "invalid reinterpretation: sizes of %0 and %1 must match">;
+
} // end of sema category
+let CategoryName = "Related Result Type Issue" in {
+// Objective-C related result type compatibility
+def warn_related_result_type_compatibility_class : Warning<
+ "method is expected to return an instance of its class type %0, but "
+ "is declared to return %1">;
+def warn_related_result_type_compatibility_protocol : Warning<
+ "protocol method is expected to return an instance of the implementing "
+ "class, but is declared to return %0">;
+def note_related_result_type_overridden : Note<
+ "overridden method is part of the '%select{|alloc|copy|init|mutableCopy|"
+ "new|autorelease|dealloc|release|retain|retainCount|self}0' method family">;
+def note_related_result_type_inferred : Note<
+ "%select{class|instance}0 method %1 is assumed to return an instance of "
+ "its receiver type (%2)">;
+
+}
+
} // end of sema component.
diff --git a/include/clang/Basic/ExceptionSpecificationType.h b/include/clang/Basic/ExceptionSpecificationType.h
index aecf6eb..98cfd29 100644
--- a/include/clang/Basic/ExceptionSpecificationType.h
+++ b/include/clang/Basic/ExceptionSpecificationType.h
@@ -18,12 +18,13 @@ namespace clang {
/// \brief The various types of exception specifications that exist in C++0x.
enum ExceptionSpecificationType {
- EST_None, ///< no exception specification
- EST_DynamicNone, ///< throw()
- EST_Dynamic, ///< throw(T1, T2)
- EST_MSAny, ///< Microsoft throw(...) extension
- EST_BasicNoexcept, ///< noexcept
- EST_ComputedNoexcept ///< noexcept(expression)
+ EST_None, ///< no exception specification
+ EST_DynamicNone, ///< throw()
+ EST_Dynamic, ///< throw(T1, T2)
+ EST_MSAny, ///< Microsoft throw(...) extension
+ EST_BasicNoexcept, ///< noexcept
+ EST_ComputedNoexcept, ///< noexcept(expression)
+ EST_Delayed ///< not known yet
};
inline bool isDynamicExceptionSpec(ExceptionSpecificationType ESpecType) {
diff --git a/include/clang/Basic/IdentifierTable.h b/include/clang/Basic/IdentifierTable.h
index 683ec83..b4eca6d 100644
--- a/include/clang/Basic/IdentifierTable.h
+++ b/include/clang/Basic/IdentifierTable.h
@@ -498,7 +498,8 @@ enum ObjCMethodFamily {
OMF_dealloc,
OMF_release,
OMF_retain,
- OMF_retainCount
+ OMF_retainCount,
+ OMF_self
};
/// Enough bits to store any enumerator in ObjCMethodFamily or
diff --git a/include/clang/Basic/LangOptions.h b/include/clang/Basic/LangOptions.h
index a5f6789..f0f1432 100644
--- a/include/clang/Basic/LangOptions.h
+++ b/include/clang/Basic/LangOptions.h
@@ -46,6 +46,8 @@ public:
unsigned ObjCNonFragileABI : 1; // Objective-C modern abi enabled
unsigned ObjCNonFragileABI2 : 1; // Objective-C enhanced modern abi enabled
unsigned ObjCDefaultSynthProperties : 1; // Objective-C auto-synthesized properties.
+ unsigned ObjCInferRelatedResultType : 1; // Infer Objective-C related return
+ // types
unsigned AppleKext : 1; // Allow apple kext features.
unsigned PascalStrings : 1; // Allow Pascal strings
@@ -173,6 +175,7 @@ public:
GC = ObjC1 = ObjC2 = ObjCNonFragileABI = ObjCNonFragileABI2 = 0;
AppleKext = 0;
ObjCDefaultSynthProperties = 0;
+ ObjCInferRelatedResultType = 0;
NoConstantCFStrings = 0; InlineVisibilityHidden = 0;
C99 = C1X = Microsoft = Borland = CPlusPlus = CPlusPlus0x = 0;
CXXOperatorNames = PascalStrings = WritableStrings = ConstStrings = 0;
diff --git a/include/clang/Basic/SourceLocation.h b/include/clang/Basic/SourceLocation.h
index 14bb2b7..ee5f96f 100644
--- a/include/clang/Basic/SourceLocation.h
+++ b/include/clang/Basic/SourceLocation.h
@@ -54,6 +54,9 @@ public:
private:
friend class SourceManager;
+ friend class ASTWriter;
+ friend class ASTReader;
+
static FileID get(unsigned V) {
FileID F;
F.ID = V;
diff --git a/include/clang/Basic/SourceManager.h b/include/clang/Basic/SourceManager.h
index c121bbb..df5074c 100644
--- a/include/clang/Basic/SourceManager.h
+++ b/include/clang/Basic/SourceManager.h
@@ -831,6 +831,14 @@ public:
return getFileCharacteristic(Loc) == SrcMgr::C_ExternCSystem;
}
+ /// \brief Returns true if the given MacroID location points at the first
+ /// token of the macro instantiation.
+ bool isAtStartOfMacroInstantiation(SourceLocation Loc) const;
+
+ /// \brief Returns true if the given MacroID location points at the last
+ /// token of the macro instantiation.
+ bool isAtEndOfMacroInstantiation(SourceLocation Loc) const;
+
//===--------------------------------------------------------------------===//
// Line Table Manipulation Routines
//===--------------------------------------------------------------------===//
diff --git a/include/clang/Basic/Specifiers.h b/include/clang/Basic/Specifiers.h
index 2f0ad9f..d21bda7 100644
--- a/include/clang/Basic/Specifiers.h
+++ b/include/clang/Basic/Specifiers.h
@@ -54,6 +54,7 @@ namespace clang {
TST_typeofType,
TST_typeofExpr,
TST_decltype, // C++0x decltype
+ TST_underlyingType, // __underlying_type for C++0x
TST_auto, // C++0x auto
TST_unknown_anytype, // __unknown_anytype extension
TST_error // erroneous type
diff --git a/include/clang/Basic/StmtNodes.td b/include/clang/Basic/StmtNodes.td
index 15ac760..03f4cc3 100644
--- a/include/clang/Basic/StmtNodes.td
+++ b/include/clang/Basic/StmtNodes.td
@@ -146,3 +146,5 @@ def SEHTryStmt : Stmt;
def SEHExceptStmt : Stmt;
def SEHFinallyStmt : Stmt;
+// OpenCL Extensions.
+def AsTypeExpr : DStmt<Expr>;
diff --git a/include/clang/Basic/TargetInfo.h b/include/clang/Basic/TargetInfo.h
index b830bf2..76006d4 100644
--- a/include/clang/Basic/TargetInfo.h
+++ b/include/clang/Basic/TargetInfo.h
@@ -368,11 +368,14 @@ public:
ConstraintInfo *OutputConstraints,
unsigned NumOutputs, unsigned &Index) const;
- virtual std::string convertConstraint(const char Constraint) const {
+ // Constraint parm will be left pointing at the last character of
+ // the constraint. In practice, it won't be changed unless the
+ // constraint is longer than one character.
+ virtual std::string convertConstraint(const char *&Constraint) const {
// 'p' defaults to 'r', but can be overridden by targets.
- if (Constraint == 'p')
+ if (*Constraint == 'p')
return std::string("r");
- return std::string(1, Constraint);
+ return std::string(1, *Constraint);
}
// Returns a string of target-specific clobbers, in LLVM format.
diff --git a/include/clang/Basic/TokenKinds.def b/include/clang/Basic/TokenKinds.def
index f9d1f4e..dfba7ee 100644
--- a/include/clang/Basic/TokenKinds.def
+++ b/include/clang/Basic/TokenKinds.def
@@ -346,6 +346,10 @@ KEYWORD(__is_polymorphic , KEYCXX)
KEYWORD(__is_trivial , KEYCXX)
KEYWORD(__is_union , KEYCXX)
+// Clang-only C++ Type Traits
+KEYWORD(__is_trivially_copyable , KEYCXX)
+KEYWORD(__underlying_type , KEYCXX)
+
// Embarcadero Expression Traits
KEYWORD(__is_lvalue_expr , KEYCXX)
KEYWORD(__is_rvalue_expr , KEYCXX)
@@ -409,6 +413,7 @@ KEYWORD(__read_write , KEYOPENCL)
ALIAS("read_only", __read_only , KEYOPENCL)
ALIAS("write_only", __write_only , KEYOPENCL)
ALIAS("read_write", __read_write , KEYOPENCL)
+KEYWORD(__builtin_astype , KEYOPENCL)
// Borland Extensions.
KEYWORD(__pascal , KEYALL)
@@ -451,6 +456,8 @@ KEYWORD(__except , KEYMS | KEYBORLAND)
KEYWORD(__finally , KEYMS | KEYBORLAND)
KEYWORD(__leave , KEYMS | KEYBORLAND)
KEYWORD(__int64 , KEYMS)
+KEYWORD(__if_exists , KEYMS)
+KEYWORD(__if_not_exists , KEYMS)
ALIAS("__int8" , char , KEYMS)
ALIAS("__int16" , short , KEYMS)
ALIAS("__int32" , int , KEYMS)
diff --git a/include/clang/Basic/TypeTraits.h b/include/clang/Basic/TypeTraits.h
index 4a2a2c6..a7a45bd 100644
--- a/include/clang/Basic/TypeTraits.h
+++ b/include/clang/Basic/TypeTraits.h
@@ -23,7 +23,7 @@ namespace clang {
UTT_HasNothrowConstructor,
UTT_HasTrivialAssign,
UTT_HasTrivialCopy,
- UTT_HasTrivialConstructor,
+ UTT_HasTrivialDefaultConstructor,
UTT_HasTrivialDestructor,
UTT_HasVirtualDestructor,
UTT_IsAbstract,
@@ -54,6 +54,7 @@ namespace clang {
UTT_IsSigned,
UTT_IsStandardLayout,
UTT_IsTrivial,
+ UTT_IsTriviallyCopyable,
UTT_IsUnion,
UTT_IsUnsigned,
UTT_IsVoid,
diff --git a/include/clang/Basic/arm_neon.td b/include/clang/Basic/arm_neon.td
index 6d6c7c7..b3da122 100644
--- a/include/clang/Basic/arm_neon.td
+++ b/include/clang/Basic/arm_neon.td
@@ -75,6 +75,7 @@ class Inst <string n, string p, string t, Op o> {
string Types = t;
Op Operand = o;
bit isShift = 0;
+ bit isVCVT_N = 0;
}
// Used to generate Builtins.def:
@@ -297,11 +298,13 @@ def VGET_LOW : Inst<"vget_low", "dk", "csilhfUcUsUiUlPcPs", OP_LO>;
def VCVT_S32 : SInst<"vcvt_s32", "xd", "fQf">;
def VCVT_U32 : SInst<"vcvt_u32", "ud", "fQf">;
def VCVT_F16 : SInst<"vcvt_f16", "hk", "f">;
-def VCVT_N_S32 : SInst<"vcvt_n_s32", "xdi", "fQf">;
-def VCVT_N_U32 : SInst<"vcvt_n_u32", "udi", "fQf">;
def VCVT_F32 : SInst<"vcvt_f32", "fd", "iUiQiQUi">;
def VCVT_F32_F16 : SInst<"vcvt_f32_f16", "fd", "h">;
+let isVCVT_N = 1 in {
+def VCVT_N_S32 : SInst<"vcvt_n_s32", "xdi", "fQf">;
+def VCVT_N_U32 : SInst<"vcvt_n_u32", "udi", "fQf">;
def VCVT_N_F32 : SInst<"vcvt_n_f32", "fdi", "iUiQiQUi">;
+}
def VMOVN : IInst<"vmovn", "hk", "silUsUiUl">;
def VMOVL : SInst<"vmovl", "wd", "csiUcUsUi">;
def VQMOVN : SInst<"vqmovn", "hk", "silUsUiUl">;
diff --git a/include/clang/Driver/CC1AsOptions.td b/include/clang/Driver/CC1AsOptions.td
index 2643c4f..b1067b7 100644
--- a/include/clang/Driver/CC1AsOptions.td
+++ b/include/clang/Driver/CC1AsOptions.td
@@ -77,3 +77,6 @@ def relax_all : Flag<"-relax-all">,
def no_exec_stack : Flag<"--noexecstack">,
HelpText<"Mark the file as not needing an executable stack">;
+
+def fatal_warnings : Flag<"--fatal-warnings">,
+ HelpText<"Consider warnings as errors">;
diff --git a/include/clang/Driver/CC1Options.td b/include/clang/Driver/CC1Options.td
index d243bf9..14d8f67 100644
--- a/include/clang/Driver/CC1Options.td
+++ b/include/clang/Driver/CC1Options.td
@@ -140,6 +140,9 @@ def femit_coverage_notes : Flag<"-femit-coverage-notes">,
HelpText<"Emit a gcov coverage notes file when compiling.">;
def femit_coverage_data: Flag<"-femit-coverage-data">,
HelpText<"Instrument the program to emit gcov coverage data when run.">;
+def coverage_file : Separate<"-coverage-file">,
+ HelpText<"Emit coverage data to this filename. The extension will be replaced.">;
+def coverage_file_EQ : Joined<"-coverage-file=">, Alias<coverage_file>;
def relaxed_aliasing : Flag<"-relaxed-aliasing">,
HelpText<"Turn off Type Based Alias Analysis">;
def masm_verbose : Flag<"-masm-verbose">,
@@ -178,6 +181,8 @@ def mconstructor_aliases : Flag<"-mconstructor-aliases">,
HelpText<"Emit complete constructors and destructors as aliases when possible">;
def mms_bitfields : Flag<"-mms-bitfields">,
HelpText<"Set the default structure layout to be compatible with the Microsoft compiler standard.">;
+def mstackrealign : Flag<"-mstackrealign">,
+ HelpText<"Force realign the stack at entry to every function.">;
def O : Joined<"-O">, HelpText<"Optimization level">;
def Os : Flag<"-Os">, HelpText<"Optimize for size">;
def Oz : Flag<"-Oz">, HelpText<"Optimize for size, regardless of performance">;
@@ -211,6 +216,8 @@ def diagnostic_log_file : Separate<"-diagnostic-log-file">,
HelpText<"Filename (or -) to log diagnostics to">;
def fno_show_column : Flag<"-fno-show-column">,
HelpText<"Do not include column number on diagnostics">;
+def fshow_column : Flag<"-fshow-column">,
+ HelpText<"Include column number on diagnostics">;
def fno_show_source_location : Flag<"-fno-show-source-location">,
HelpText<"Do not include source location information with diagnostics">;
def fshow_overloads_EQ : Joined<"-fshow-overloads=">,
@@ -240,6 +247,8 @@ def fdiagnostics_show_name : Flag<"-fdiagnostics-show-name">,
HelpText<"Print diagnostic name">;
def fdiagnostics_show_option : Flag<"-fdiagnostics-show-option">,
HelpText<"Print option name with mappable diagnostics">;
+def fdiagnostics_format : Separate<"-fdiagnostics-format">,
+ HelpText<"Change diagnostic formatting to match IDE and command line tools">;
def fdiagnostics_show_category : Separate<"-fdiagnostics-show-category">,
HelpText<"Print diagnostic category">;
def fdiagnostics_show_note_include_stack :
@@ -414,6 +423,8 @@ def fno_assume_sane_operator_new : Flag<"-fno-assume-sane-operator-new">,
HelpText<"Don't assume that C++'s global operator new can't alias any pointer">;
def fgnu_keywords : Flag<"-fgnu-keywords">,
HelpText<"Allow GNU-extension keywords regardless of language standard">;
+def fgnu89_inline : Flag<"-fgnu89-inline">,
+ HelpText<"Use the gnu89 inline semantics">;
def fno_gnu_keywords : Flag<"-fno-gnu-keywords">,
HelpText<"Disallow GNU-extension keywords regardless of language standard">;
def fdollars_in_identifiers : Flag<"-fdollars-in-identifiers">,
@@ -482,6 +493,8 @@ def print_ivar_layout : Flag<"-print-ivar-layout">,
HelpText<"Enable Objective-C Ivar layout bitmap print trace">;
def fobjc_nonfragile_abi : Flag<"-fobjc-nonfragile-abi">,
HelpText<"enable objective-c's nonfragile abi">;
+def fobjc_infer_related_result_type : Flag<"-fobjc-infer-related-result-type">,
+ HelpText<"infer Objective-C related result type based on method family">;
def ftrapv : Flag<"-ftrapv">,
HelpText<"Trap on integer overflow">;
def ftrapv_handler : Separate<"-ftrapv-handler">,
diff --git a/include/clang/Driver/Options.td b/include/clang/Driver/Options.td
index 38f0c57..7203976 100644
--- a/include/clang/Driver/Options.td
+++ b/include/clang/Driver/Options.td
@@ -238,8 +238,8 @@ def emit_llvm : Flag<"-emit-llvm">,
def exported__symbols__list : Separate<"-exported_symbols_list">;
def e : JoinedOrSeparate<"-e">;
def fPIC : Flag<"-fPIC">, Group<f_Group>;
-def fPIE : Flag<"-fPIE">, Group<f_Group>;
-def fno_PIE : Flag<"-fno-PIE">, Group<f_Group>;
+def fPIE : Flag<"-fPIE">, Group<f_Group>, Flags<[NoArgumentUnused]>;
+def fno_PIE : Flag<"-fno-PIE">, Group<f_Group>, Flags<[NoArgumentUnused]>;
def faccess_control : Flag<"-faccess-control">, Group<f_Group>;
def fallow_unsupported : Flag<"-fallow-unsupported">, Group<f_Group>;
def fapple_kext : Flag<"-fapple-kext">, Group<f_Group>;
@@ -278,6 +278,7 @@ def fdiagnostics_parseable_fixits : Flag<"-fdiagnostics-parseable-fixits">, Grou
def fdiagnostics_show_option : Flag<"-fdiagnostics-show-option">, Group<f_Group>;
def fdiagnostics_show_name : Flag<"-fdiagnostics-show-name">, Group<f_Group>;
def fdiagnostics_show_note_include_stack : Flag<"-fdiagnostics-show-note-include-stack">, Group<f_Group>;
+def fdiagnostics_format_EQ : Joined<"-fdiagnostics-format=">, Group<f_clang_Group>;
def fdiagnostics_show_category_EQ : Joined<"-fdiagnostics-show-category=">, Group<f_clang_Group>;
def fdollars_in_identifiers : Flag<"-fdollars-in-identifiers">, Group<f_Group>;
def fdwarf2_cfi_asm : Flag<"-fdwarf2-cfi-asm">, Group<f_Group>;
@@ -298,6 +299,8 @@ def fno_for_scope : Flag<"-fno-for-scope">, Group<f_Group>;
def ffreestanding : Flag<"-ffreestanding">, Group<f_Group>;
def fgnu_keywords : Flag<"-fgnu-keywords">, Group<f_Group>;
+def fgnu89_inline : Flag<"-fgnu89-inline">, Group<f_Group>;
+def fno_gnu89_inline : Flag<"-fno-gnu89-inline">, Group<f_Group>;
def fgnu_runtime : Flag<"-fgnu-runtime">, Group<f_Group>;
def fheinous_gnu_extensions : Flag<"-fheinous-gnu-extensions">;
def filelist : Separate<"-filelist">, Flags<[LinkerInput]>;
@@ -389,6 +392,10 @@ def fobjc_gc_only : Flag<"-fobjc-gc-only">, Group<f_Group>;
def fobjc_gc : Flag<"-fobjc-gc">, Group<f_Group>;
def fobjc_legacy_dispatch : Flag<"-fobjc-legacy-dispatch">, Group<f_Group>;
def fobjc_new_property : Flag<"-fobjc-new-property">, Group<clang_ignored_f_Group>;
+def fobjc_infer_related_result_type : Flag<"-fobjc-infer-related-result-type">,
+ Group<f_Group>;
+def fno_objc_infer_related_result_type : Flag<
+ "-fno-objc-infer-related-result-type">, Group<f_Group>;
// Objective-C ABI options.
def fobjc_abi_version_EQ : Joined<"-fobjc-abi-version=">, Group<f_Group>;
@@ -406,8 +413,8 @@ def foutput_class_dir_EQ : Joined<"-foutput-class-dir=">, Group<f_Group>;
def fpascal_strings : Flag<"-fpascal-strings">, Group<f_Group>;
def fpch_preprocess : Flag<"-fpch-preprocess">, Group<f_Group>;
def fpic : Flag<"-fpic">, Group<f_Group>;
-def fpie : Flag<"-fpie">, Group<f_Group>;
-def fno_pie : Flag<"-fno-pie">, Group<f_Group>;
+def fpie : Flag<"-fpie">, Group<f_Group>, Flags<[NoArgumentUnused]>;
+def fno_pie : Flag<"-fno-pie">, Group<f_Group>, Flags<[NoArgumentUnused]>;
def fprofile_arcs : Flag<"-fprofile-arcs">, Group<f_Group>;
def fprofile_generate : Flag<"-fprofile-generate">, Group<f_Group>;
def framework : Separate<"-framework">, Flags<[LinkerInput]>;
@@ -418,6 +425,7 @@ def fshort_enums : Flag<"-fshort-enums">, Group<f_Group>;
def freorder_blocks : Flag<"-freorder-blocks">, Group<clang_ignored_f_Group>;
def fshort_wchar : Flag<"-fshort-wchar">, Group<f_Group>;
def fshow_overloads_EQ : Joined<"-fshow-overloads=">, Group<f_Group>;
+def fshow_column : Flag<"-fshow-column">, Group<f_Group>;
def fshow_source_location : Flag<"-fshow-source-location">, Group<f_Group>;
def fspell_checking : Flag<"-fspell-checking">, Group<f_Group>;
def fsigned_bitfields : Flag<"-fsigned-bitfields">, Group<f_Group>;
@@ -513,6 +521,7 @@ def mlinker_version_EQ : Joined<"-mlinker-version=">, Flags<[NoForward]>;
def mllvm : Separate<"-mllvm">;
def mmacosx_version_min_EQ : Joined<"-mmacosx-version-min=">, Group<m_Group>;
def mms_bitfields : Flag<"-mms-bitfields">, Group<m_Group>;
+def mstackrealign : Flag<"-mstackrealign">, Group<m_Group>;
def mmmx : Flag<"-mmmx">, Group<m_x86_Features_Group>;
def mno_3dnowa : Flag<"-mno-3dnowa">, Group<m_x86_Features_Group>;
def mno_3dnow : Flag<"-mno-3dnow">, Group<m_x86_Features_Group>;
diff --git a/include/clang/Driver/ToolChain.h b/include/clang/Driver/ToolChain.h
index da6949f..626d54c 100644
--- a/include/clang/Driver/ToolChain.h
+++ b/include/clang/Driver/ToolChain.h
@@ -157,7 +157,7 @@ public:
virtual bool SupportsProfiling() const { return true; }
/// Does this tool chain support Objective-C garbage collection.
- virtual bool SupportsObjCGC() const { return false; }
+ virtual bool SupportsObjCGC() const { return true; }
/// UseDwarfDebugFlags - Embed the compile options to clang into the Dwarf
/// compile unit information.
diff --git a/include/clang/Frontend/ASTUnit.h b/include/clang/Frontend/ASTUnit.h
index 57c59d9..339297e 100644
--- a/include/clang/Frontend/ASTUnit.h
+++ b/include/clang/Frontend/ASTUnit.h
@@ -51,6 +51,7 @@ class HeaderSearch;
class Preprocessor;
class SourceManager;
class TargetInfo;
+class ASTFrontendAction;
using namespace idx;
@@ -248,6 +249,10 @@ private:
/// \brief Whether we should be caching code-completion results.
bool ShouldCacheCodeCompletionResults;
+ /// \brief Whether we want to include nested macro instantiations in the
+ /// detailed preprocessing record.
+ bool NestedMacroInstantiations;
+
static void ConfigureDiags(llvm::IntrusiveRefCntPtr<Diagnostic> &Diags,
const char **ArgBegin, const char **ArgEnd,
ASTUnit &AST, bool CaptureDiagnostics);
@@ -574,6 +579,21 @@ private:
public:
+ /// \brief Create an ASTUnit from a source file, via a CompilerInvocation
+ /// object, by invoking the optionally provided ASTFrontendAction.
+ ///
+ /// \param CI - The compiler invocation to use; it must have exactly one input
+ /// source file. The ASTUnit takes ownership of the CompilerInvocation object.
+ ///
+ /// \param Diags - The diagnostics engine to use for reporting errors; its
+ /// lifetime is expected to extend past that of the returned ASTUnit.
+ ///
+ /// \param Action - The ASTFrontendAction to invoke. Its ownership is not
+ /// transfered.
+ static ASTUnit *LoadFromCompilerInvocationAction(CompilerInvocation *CI,
+ llvm::IntrusiveRefCntPtr<Diagnostic> Diags,
+ ASTFrontendAction *Action = 0);
+
/// LoadFromCompilerInvocation - Create an ASTUnit from a source file, via a
/// CompilerInvocation object.
///
@@ -591,7 +611,8 @@ public:
bool CaptureDiagnostics = false,
bool PrecompilePreamble = false,
bool CompleteTranslationUnit = true,
- bool CacheCodeCompletionResults = false);
+ bool CacheCodeCompletionResults = false,
+ bool NestedMacroInstantiations = true);
/// LoadFromCommandLine - Create an ASTUnit from a vector of command line
/// arguments, which must specify exactly one source file.
@@ -620,7 +641,8 @@ public:
bool CompleteTranslationUnit = true,
bool CacheCodeCompletionResults = false,
bool CXXPrecompilePreamble = false,
- bool CXXChainedPCH = false);
+ bool CXXChainedPCH = false,
+ bool NestedMacroInstantiations = true);
/// \brief Reparse the source files using the same command-line options that
/// were originally used to produce this translation unit.
diff --git a/include/clang/Frontend/CodeGenOptions.h b/include/clang/Frontend/CodeGenOptions.h
index 8bef6a3..1c686c7 100644
--- a/include/clang/Frontend/CodeGenOptions.h
+++ b/include/clang/Frontend/CodeGenOptions.h
@@ -95,6 +95,10 @@ public:
/// The code model to use (-mcmodel).
std::string CodeModel;
+ /// The filename with path we use for coverage files. The extension will be
+ /// replaced.
+ std::string CoverageFile;
+
/// Enable additional debugging information.
std::string DebugPass;
diff --git a/include/clang/Frontend/DiagnosticOptions.h b/include/clang/Frontend/DiagnosticOptions.h
index ff92058..56093c3 100644
--- a/include/clang/Frontend/DiagnosticOptions.h
+++ b/include/clang/Frontend/DiagnosticOptions.h
@@ -37,6 +37,10 @@ public:
unsigned ShowNoteIncludeStack : 1; /// Show include stacks for notes.
unsigned ShowCategories : 2; /// Show categories: 0 -> none, 1 -> Number,
/// 2 -> Full Name.
+
+ unsigned Format : 2; /// Format for diagnostics:
+ enum TextDiagnosticFormat { Clang, Msvc, Vi };
+
unsigned ShowColors : 1; /// Show diagnostics with ANSI color sequences.
unsigned ShowOverloads : 1; /// Overload candidates to show. Values from
/// Diagnostic::OverloadsShown
@@ -86,6 +90,7 @@ public:
ShowNames = 0;
ShowOptionNames = 0;
ShowCategories = 0;
+ Format = Clang;
ShowSourceRanges = 0;
ShowParseableFixits = 0;
VerifyDiagnostics = 0;
diff --git a/include/clang/Frontend/LangStandard.h b/include/clang/Frontend/LangStandard.h
index 74ca519..ea37bdd 100644
--- a/include/clang/Frontend/LangStandard.h
+++ b/include/clang/Frontend/LangStandard.h
@@ -18,14 +18,15 @@ namespace frontend {
enum LangFeatures {
BCPLComment = (1 << 0),
- C99 = (1 << 1),
- C1X = (1 << 2),
- CPlusPlus = (1 << 3),
- CPlusPlus0x = (1 << 4),
- Digraphs = (1 << 5),
- GNUMode = (1 << 6),
- HexFloat = (1 << 7),
- ImplicitInt = (1 << 8)
+ C89 = (1 << 1),
+ C99 = (1 << 2),
+ C1X = (1 << 3),
+ CPlusPlus = (1 << 4),
+ CPlusPlus0x = (1 << 5),
+ Digraphs = (1 << 6),
+ GNUMode = (1 << 7),
+ HexFloat = (1 << 8),
+ ImplicitInt = (1 << 9)
};
}
@@ -54,6 +55,9 @@ public:
/// hasBCPLComments - Language supports '//' comments.
bool hasBCPLComments() const { return Flags & frontend::BCPLComment; }
+ /// isC89 - Language is a superset of C89.
+ bool isC89() const { return Flags & frontend::C89; }
+
/// isC99 - Language is a superset of C99.
bool isC99() const { return Flags & frontend::C99; }
diff --git a/include/clang/Frontend/LangStandards.def b/include/clang/Frontend/LangStandards.def
index 586e5c8..6055ad5 100644
--- a/include/clang/Frontend/LangStandards.def
+++ b/include/clang/Frontend/LangStandards.def
@@ -22,21 +22,21 @@
// C89-ish modes.
LANGSTANDARD(c89, "c89",
"ISO C 1990",
- ImplicitInt)
+ C89 | ImplicitInt)
LANGSTANDARD(c90, "c90",
"ISO C 1990",
- ImplicitInt)
+ C89 | ImplicitInt)
LANGSTANDARD(iso9899_1990, "iso9899:1990",
"ISO C 1990",
- ImplicitInt)
+ C89 | ImplicitInt)
LANGSTANDARD(c94, "iso9899:199409",
"ISO C 1990 with amendment 1",
- Digraphs | ImplicitInt)
+ C89 | Digraphs | ImplicitInt)
LANGSTANDARD(gnu89, "gnu89",
"ISO C 1990 with GNU extensions",
- BCPLComment | Digraphs | GNUMode | ImplicitInt)
+ BCPLComment | C89 | Digraphs | GNUMode | ImplicitInt)
// C99-ish modes
LANGSTANDARD(c99, "c99",
@@ -87,7 +87,6 @@ LANGSTANDARD(gnucxx0x, "gnu++0x",
BCPLComment | CPlusPlus | CPlusPlus0x | Digraphs | GNUMode)
// OpenCL
-
LANGSTANDARD(opencl, "cl",
"OpenCL 1.0",
BCPLComment | C99 | Digraphs | HexFloat)
diff --git a/include/clang/Frontend/PreprocessorOptions.h b/include/clang/Frontend/PreprocessorOptions.h
index e875ec1..e471c5c 100644
--- a/include/clang/Frontend/PreprocessorOptions.h
+++ b/include/clang/Frontend/PreprocessorOptions.h
@@ -41,6 +41,10 @@ public:
/// record of all macro definitions and
/// instantiations.
+ /// \brief Whether the detailed preprocessing record includes nested macro
+ /// instantiations.
+ unsigned DetailedRecordIncludesNestedMacroInstantiations : 1;
+
/// The implicit PCH included at the start of the translation unit, or empty.
std::string ImplicitPCHInclude;
@@ -136,6 +140,7 @@ public:
public:
PreprocessorOptions() : UsePredefines(true), DetailedRecord(false),
+ DetailedRecordIncludesNestedMacroInstantiations(true),
DisablePCHValidation(false), DisableStatCache(false),
DumpDeserializedPCHDecls(false),
PrecompiledPreambleBytes(0, true),
diff --git a/include/clang/Frontend/Utils.h b/include/clang/Frontend/Utils.h
index e499716..3c34c2d 100644
--- a/include/clang/Frontend/Utils.h
+++ b/include/clang/Frontend/Utils.h
@@ -71,9 +71,6 @@ void ProcessWarningOptions(Diagnostic &Diags, const DiagnosticOptions &Opts);
void DoPrintPreprocessedInput(Preprocessor &PP, llvm::raw_ostream* OS,
const PreprocessorOutputOptions &Opts);
-/// CheckDiagnostics - Gather the expected diagnostics and check them.
-bool CheckDiagnostics(Preprocessor &PP);
-
/// AttachDependencyFileGen - Create a dependency file generator, and attach
/// it to the given preprocessor. This takes ownership of the output stream.
void AttachDependencyFileGen(Preprocessor &PP,
diff --git a/include/clang/Lex/HeaderSearch.h b/include/clang/Lex/HeaderSearch.h
index fec4dad..5e36d8e 100644
--- a/include/clang/Lex/HeaderSearch.h
+++ b/include/clang/Lex/HeaderSearch.h
@@ -31,6 +31,9 @@ struct HeaderFileInfo {
/// isImport - True if this is a #import'd or #pragma once file.
unsigned isImport : 1;
+ /// isPragmaOnce - True if this is #pragma once file.
+ unsigned isPragmaOnce : 1;
+
/// DirInfo - Keep track of whether this is a system header, and if so,
/// whether it is C++ clean or not. This can be set by the include paths or
/// by #pragma gcc system_header. This is an instance of
@@ -66,8 +69,8 @@ struct HeaderFileInfo {
const IdentifierInfo *ControllingMacro;
HeaderFileInfo()
- : isImport(false), DirInfo(SrcMgr::C_User), External(false),
- Resolved(false), NumIncludes(0), ControllingMacroID(0),
+ : isImport(false), isPragmaOnce(false), DirInfo(SrcMgr::C_User),
+ External(false), Resolved(false), NumIncludes(0), ControllingMacroID(0),
ControllingMacro(0) {}
/// \brief Retrieve the controlling macro for this header file, if
@@ -77,7 +80,8 @@ struct HeaderFileInfo {
/// \brief Determine whether this is a non-default header file info, e.g.,
/// it corresponds to an actual header we've included or tried to include.
bool isNonDefault() const {
- return isImport || NumIncludes || ControllingMacro || ControllingMacroID;
+ return isImport || isPragmaOnce || NumIncludes || ControllingMacro ||
+ ControllingMacroID;
}
};
@@ -101,11 +105,12 @@ class HeaderSearch {
FileManager &FileMgr;
/// #include search path information. Requests for #include "x" search the
/// directory of the #including file first, then each directory in SearchDirs
- /// consequtively. Requests for <x> search the current dir first, then each
- /// directory in SearchDirs, starting at SystemDirIdx, consequtively. If
+ /// consecutively. Requests for <x> search the current dir first, then each
+ /// directory in SearchDirs, starting at AngledDirIdx, consecutively. If
/// NoCurDirSearch is true, then the check for the file in the current
/// directory is suppressed.
std::vector<DirectoryLookup> SearchDirs;
+ unsigned AngledDirIdx;
unsigned SystemDirIdx;
bool NoCurDirSearch;
@@ -156,8 +161,12 @@ public:
/// SetSearchPaths - Interface for setting the file search paths.
///
void SetSearchPaths(const std::vector<DirectoryLookup> &dirs,
- unsigned systemDirIdx, bool noCurDirSearch) {
+ unsigned angledDirIdx, unsigned systemDirIdx,
+ bool noCurDirSearch) {
+ assert(angledDirIdx <= systemDirIdx && systemDirIdx <= dirs.size() &&
+ "Directory indicies are unordered");
SearchDirs = dirs;
+ AngledDirIdx = angledDirIdx;
SystemDirIdx = systemDirIdx;
NoCurDirSearch = noCurDirSearch;
//LookupFileCache.clear();
@@ -242,7 +251,9 @@ public:
/// MarkFileIncludeOnce - Mark the specified file as a "once only" file, e.g.
/// due to #pragma once.
void MarkFileIncludeOnce(const FileEntry *File) {
- getFileInfo(File).isImport = true;
+ HeaderFileInfo &FI = getFileInfo(File);
+ FI.isImport = true;
+ FI.isPragmaOnce = true;
}
/// MarkFileSystemHeader - Mark the specified file as a system header, e.g.
@@ -265,6 +276,13 @@ public:
getFileInfo(File).ControllingMacro = ControllingMacro;
}
+ /// \brief Determine whether this file is intended to be safe from
+ /// multiple inclusions, e.g., it has #pragma once or a controlling
+ /// macro.
+ ///
+ /// This routine does not consider the effect of #import
+ bool isFileMultipleIncludeGuarded(const FileEntry *File);
+
/// CreateHeaderMap - This method returns a HeaderMap for the specified
/// FileEntry, uniquing them through the the 'HeaderMaps' datastructure.
const HeaderMap *CreateHeaderMap(const FileEntry *FE);
@@ -285,6 +303,20 @@ public:
search_dir_iterator search_dir_end() const { return SearchDirs.end(); }
unsigned search_dir_size() const { return SearchDirs.size(); }
+ search_dir_iterator quoted_dir_begin() const {
+ return SearchDirs.begin();
+ }
+ search_dir_iterator quoted_dir_end() const {
+ return SearchDirs.begin() + AngledDirIdx;
+ }
+
+ search_dir_iterator angled_dir_begin() const {
+ return SearchDirs.begin() + AngledDirIdx;
+ }
+ search_dir_iterator angled_dir_end() const {
+ return SearchDirs.begin() + SystemDirIdx;
+ }
+
search_dir_iterator system_dir_begin() const {
return SearchDirs.begin() + SystemDirIdx;
}
diff --git a/include/clang/Lex/LiteralSupport.h b/include/clang/Lex/LiteralSupport.h
index dcaf445..ec3d9c5 100644
--- a/include/clang/Lex/LiteralSupport.h
+++ b/include/clang/Lex/LiteralSupport.h
@@ -156,7 +156,9 @@ public:
StringLiteralParser(const Token *StringToks, unsigned NumStringToks,
const SourceManager &sm, const LangOptions &features,
const TargetInfo &target, Diagnostic *diags = 0)
- : SM(sm), Features(features), Target(target), Diags(diags) {
+ : SM(sm), Features(features), Target(target), Diags(diags),
+ MaxTokenLength(0), SizeBound(0), wchar_tByteWidth(0),
+ ResultPtr(ResultBuf.data()), hadError(false), AnyWide(false), Pascal(false) {
init(StringToks, NumStringToks);
}
@@ -165,8 +167,8 @@ public:
bool AnyWide;
bool Pascal;
- const char *GetString() { return &ResultBuf[0]; }
- unsigned GetStringLength() const { return ResultPtr-&ResultBuf[0]; }
+ const char *GetString() { return ResultBuf.data(); }
+ unsigned GetStringLength() const { return ResultPtr-ResultBuf.data(); }
unsigned GetNumStringChars() const {
if (AnyWide)
diff --git a/include/clang/Lex/PreprocessingRecord.h b/include/clang/Lex/PreprocessingRecord.h
index 7be8455..e498e9d 100644
--- a/include/clang/Lex/PreprocessingRecord.h
+++ b/include/clang/Lex/PreprocessingRecord.h
@@ -258,6 +258,10 @@ namespace clang {
/// including the various preprocessing directives processed, macros
/// instantiated, etc.
class PreprocessingRecord : public PPCallbacks {
+ /// \brief Whether we should include nested macro instantiations in
+ /// the preprocessing record.
+ bool IncludeNestedMacroInstantiations;
+
/// \brief Allocator used to store preprocessing objects.
llvm::BumpPtrAllocator BumpAlloc;
@@ -281,7 +285,8 @@ namespace clang {
void MaybeLoadPreallocatedEntities() const ;
public:
- PreprocessingRecord();
+ /// \brief Construct
+ explicit PreprocessingRecord(bool IncludeNestedMacroInstantiations);
/// \brief Allocate memory in the preprocessing record.
void *Allocate(unsigned Size, unsigned Align = 8) {
@@ -291,6 +296,10 @@ namespace clang {
/// \brief Deallocate memory in the preprocessing record.
void Deallocate(void *Ptr) { }
+ size_t getTotalMemory() const {
+ return BumpAlloc.getTotalMemory();
+ }
+
// Iteration over the preprocessed entities.
typedef std::vector<PreprocessedEntity *>::iterator iterator;
typedef std::vector<PreprocessedEntity *>::const_iterator const_iterator;
diff --git a/include/clang/Lex/Preprocessor.h b/include/clang/Lex/Preprocessor.h
index 616507a..76e3f59 100644
--- a/include/clang/Lex/Preprocessor.h
+++ b/include/clang/Lex/Preprocessor.h
@@ -84,6 +84,7 @@ class Preprocessor : public llvm::RefCountedBase<Preprocessor> {
IdentifierInfo *Ident_Pragma, *Ident__pragma; // _Pragma, __pragma
IdentifierInfo *Ident__VA_ARGS__; // __VA_ARGS__
IdentifierInfo *Ident__has_feature; // __has_feature
+ IdentifierInfo *Ident__has_extension; // __has_extension
IdentifierInfo *Ident__has_builtin; // __has_builtin
IdentifierInfo *Ident__has_attribute; // __has_attribute
IdentifierInfo *Ident__has_include; // __has_include
@@ -441,7 +442,7 @@ public:
/// \brief Create a new preprocessing record, which will keep track of
/// all macro expansions, macro definitions, etc.
- void createPreprocessingRecord();
+ void createPreprocessingRecord(bool IncludeNestedMacroInstantiations);
/// EnterMainSourceFile - Enter the specified FileID as the main source file,
/// which implicitly adds the builtin defines etc.
diff --git a/include/clang/Parse/Parser.h b/include/clang/Parse/Parser.h
index 3fd9844..e4cdc27 100644
--- a/include/clang/Parse/Parser.h
+++ b/include/clang/Parse/Parser.h
@@ -580,6 +580,18 @@ private:
/// ExitScope - Pop a scope off the scope stack.
void ExitScope();
+ /// \brief RAII object used to modify the scope flags for the current scope.
+ class ParseScopeFlags {
+ Scope *CurScope;
+ unsigned OldFlags;
+ ParseScopeFlags(const ParseScopeFlags &); // do not implement
+ void operator=(const ParseScopeFlags &); // do not implement
+
+ public:
+ ParseScopeFlags(Parser *Self, unsigned ScopeFlags, bool ManageFlags = true);
+ ~ParseScopeFlags();
+ };
+
//===--------------------------------------------------------------------===//
// Diagnostic Emission and Error recovery.
@@ -621,8 +633,8 @@ private:
/// - function bodies
/// - default arguments
/// - exception-specifications (TODO: C++0x)
- /// - and brace-or-equal-initializers (TODO: C++0x)
- /// for non-static data members (including such things in nested classes)."
+ /// - and brace-or-equal-initializers for non-static data members
+ /// (including such things in nested classes)."
/// LateParsedDeclarations build the tree of those elements so they can
/// be parsed after parsing the top-level class.
class LateParsedDeclaration {
@@ -630,6 +642,7 @@ private:
virtual ~LateParsedDeclaration();
virtual void ParseLexedMethodDeclarations();
+ virtual void ParseLexedMemberInitializers();
virtual void ParseLexedMethodDefs();
};
@@ -641,6 +654,7 @@ private:
virtual ~LateParsedClass();
virtual void ParseLexedMethodDeclarations();
+ virtual void ParseLexedMemberInitializers();
virtual void ParseLexedMethodDefs();
private:
@@ -714,6 +728,25 @@ private:
llvm::SmallVector<LateParsedDefaultArgument, 8> DefaultArgs;
};
+ /// LateParsedMemberInitializer - An initializer for a non-static class data
+ /// member whose parsing must to be delayed until the class is completely
+ /// defined (C++11 [class.mem]p2).
+ struct LateParsedMemberInitializer : public LateParsedDeclaration {
+ LateParsedMemberInitializer(Parser *P, Decl *FD)
+ : Self(P), Field(FD) { }
+
+ virtual void ParseLexedMemberInitializers();
+
+ Parser *Self;
+
+ /// Field - The field declaration.
+ Decl *Field;
+
+ /// CachedTokens - The sequence of tokens that comprises the initializer,
+ /// including any leading '='.
+ CachedTokens Toks;
+ };
+
/// LateParsedDeclarationsContainer - During parsing of a top (non-nested)
/// C++ class, its method declarations that contain parts that won't be
/// parsed until after the definition is completed (C++ [class.mem]p2),
@@ -973,11 +1006,14 @@ private:
Decl *ParseCXXInlineMethodDef(AccessSpecifier AS, ParsingDeclarator &D,
const ParsedTemplateInfo &TemplateInfo,
- const VirtSpecifiers& VS);
+ const VirtSpecifiers& VS, ExprResult& Init);
+ void ParseCXXNonStaticMemberInitializer(Decl *VarD);
void ParseLexedMethodDeclarations(ParsingClass &Class);
void ParseLexedMethodDeclaration(LateParsedMethodDeclaration &LM);
void ParseLexedMethodDefs(ParsingClass &Class);
void ParseLexedMethodDef(LexedMethod &LM);
+ void ParseLexedMemberInitializers(ParsingClass &Class);
+ void ParseLexedMemberInitializer(LateParsedMemberInitializer &MI);
bool ConsumeAndStoreUntil(tok::TokenKind T1,
CachedTokens &Toks,
bool StopAtSemi = true,
@@ -1000,7 +1036,7 @@ private:
DeclGroupPtrTy ParseExternalDeclaration(ParsedAttributesWithRange &attrs,
ParsingDeclSpec *DS = 0);
- bool isDeclarationAfterDeclarator() const;
+ bool isDeclarationAfterDeclarator();
bool isStartOfFunctionDefinition(const ParsingDeclarator &Declarator);
DeclGroupPtrTy ParseDeclarationOrFunctionDefinition(ParsedAttributes &attrs,
AccessSpecifier AS = AS_none);
@@ -1308,7 +1344,12 @@ private:
StmtResult ParseReturnStatement(ParsedAttributes &Attr);
StmtResult ParseAsmStatement(bool &msAsm);
StmtResult FuzzyParseMicrosoftAsmStatement(SourceLocation AsmLoc);
- bool ParseAsmOperandsOpt(llvm::SmallVectorImpl<IdentifierInfo *> &Names,
+ bool ParseMicrosoftIfExistsCondition(bool& Result);
+ void ParseMicrosoftIfExistsStatement(StmtVector &Stmts);
+ void ParseMicrosoftIfExistsExternalDeclaration();
+ void ParseMicrosoftIfExistsClassDeclaration(DeclSpec::TST TagType,
+ AccessSpecifier& CurAS);
+bool ParseAsmOperandsOpt(llvm::SmallVectorImpl<IdentifierInfo *> &Names,
llvm::SmallVectorImpl<ExprTy *> &Constraints,
llvm::SmallVectorImpl<ExprTy *> &Exprs);
@@ -1645,6 +1686,7 @@ private:
void ParseTypeofSpecifier(DeclSpec &DS);
void ParseDecltypeSpecifier(DeclSpec &DS);
+ void ParseUnderlyingTypeSpecifier(DeclSpec &DS);
ExprResult ParseCXX0XAlignArgument(SourceLocation Start);
@@ -1714,6 +1756,12 @@ private:
Decl *ParseNamespace(unsigned Context, SourceLocation &DeclEnd,
SourceLocation InlineLoc = SourceLocation());
+ void ParseInnerNamespace(std::vector<SourceLocation>& IdentLoc,
+ std::vector<IdentifierInfo*>& Ident,
+ std::vector<SourceLocation>& NamespaceLoc,
+ unsigned int index, SourceLocation& InlineLoc,
+ SourceLocation& LBrace, ParsedAttributes& attrs,
+ SourceLocation& RBraceLoc);
Decl *ParseLinkage(ParsingDeclSpec &DS, unsigned Context);
Decl *ParseUsingDirectiveOrDeclaration(unsigned Context,
const ParsedTemplateInfo &TemplateInfo,
@@ -1743,6 +1791,8 @@ private:
bool SuppressDeclarations = false);
void ParseCXXMemberSpecification(SourceLocation StartLoc, unsigned TagType,
Decl *TagDecl);
+ ExprResult ParseCXXMemberInitializer(bool IsFunction,
+ SourceLocation &EqualLoc);
void ParseCXXClassMemberDeclaration(AccessSpecifier AS,
const ParsedTemplateInfo &TemplateInfo = ParsedTemplateInfo(),
ParsingDeclRAIIObject *DiagsFromTParams = 0);
diff --git a/include/clang/Sema/CodeCompleteConsumer.h b/include/clang/Sema/CodeCompleteConsumer.h
index 882440b..d322180 100644
--- a/include/clang/Sema/CodeCompleteConsumer.h
+++ b/include/clang/Sema/CodeCompleteConsumer.h
@@ -88,7 +88,10 @@ enum {
/// \brief Adjustment for KVC code pattern priorities when it doesn't look
/// like the
- CCD_ProbablyNotObjCCollection = 15
+ CCD_ProbablyNotObjCCollection = 15,
+
+ /// \brief An Objective-C method being used as a property.
+ CCD_MethodAsProperty = 2
};
/// \brief Priority value factors by which we will divide or multiply the
diff --git a/include/clang/Sema/DeclSpec.h b/include/clang/Sema/DeclSpec.h
index 708c9b2..7ce4e00 100644
--- a/include/clang/Sema/DeclSpec.h
+++ b/include/clang/Sema/DeclSpec.h
@@ -249,6 +249,7 @@ public:
static const TST TST_typeofType = clang::TST_typeofType;
static const TST TST_typeofExpr = clang::TST_typeofExpr;
static const TST TST_decltype = clang::TST_decltype;
+ static const TST TST_underlyingType = clang::TST_underlyingType;
static const TST TST_auto = clang::TST_auto;
static const TST TST_unknown_anytype = clang::TST_unknown_anytype;
static const TST TST_error = clang::TST_error;
@@ -344,7 +345,8 @@ private:
void SaveStorageSpecifierAsWritten();
static bool isTypeRep(TST T) {
- return (T == TST_typename || T == TST_typeofType);
+ return (T == TST_typename || T == TST_typeofType ||
+ T == TST_underlyingType);
}
static bool isExprRep(TST T) {
return (T == TST_typeofExpr || T == TST_decltype);
@@ -462,6 +464,14 @@ public:
SourceLocation getRestrictSpecLoc() const { return TQ_restrictLoc; }
SourceLocation getVolatileSpecLoc() const { return TQ_volatileLoc; }
+ /// \brief Clear out all of the type qualifiers.
+ void ClearTypeQualifiers() {
+ TypeQualifiers = 0;
+ TQ_constLoc = SourceLocation();
+ TQ_restrictLoc = SourceLocation();
+ TQ_volatileLoc = SourceLocation();
+ }
+
// function-specifier
bool isInlineSpecified() const { return FS_inline_specified; }
SourceLocation getInlineSpecLoc() const { return FS_inlineLoc; }
@@ -1068,8 +1078,8 @@ struct DeclaratorChunk {
/// If this is an invalid location, there is no ref-qualifier.
unsigned RefQualifierLoc;
- /// \brief When ExceptionSpecType isn't EST_None, the location of the
- /// keyword introducing the spec.
+ /// \brief When ExceptionSpecType isn't EST_None or EST_Delayed, the
+ /// location of the keyword introducing the spec.
unsigned ExceptionSpecLoc;
/// ArgInfo - This is a pointer to a new[]'d array of ParamInfo objects that
@@ -1332,7 +1342,8 @@ public:
CXXCatchContext, // C++ catch exception-declaration
BlockLiteralContext, // Block literal declarator.
TemplateTypeArgContext, // Template type argument.
- AliasDeclContext // C++0x alias-declaration.
+ AliasDeclContext, // C++0x alias-declaration.
+ AliasTemplateContext // C++0x alias-declaration template.
};
private:
@@ -1474,6 +1485,7 @@ public:
case TypeNameContext:
case AliasDeclContext:
+ case AliasTemplateContext:
case PrototypeContext:
case ObjCPrototypeContext:
case TemplateParamContext:
@@ -1503,6 +1515,7 @@ public:
case TypeNameContext:
case AliasDeclContext:
+ case AliasTemplateContext:
case ObjCPrototypeContext:
case BlockLiteralContext:
case TemplateTypeArgContext:
@@ -1531,6 +1544,7 @@ public:
case CXXCatchContext:
case TypeNameContext:
case AliasDeclContext:
+ case AliasTemplateContext:
case BlockLiteralContext:
case TemplateTypeArgContext:
return false;
@@ -1602,6 +1616,29 @@ public:
DeclTypeInfo.erase(DeclTypeInfo.begin());
}
+ /// isArrayOfUnknownBound - This method returns true if the declarator
+ /// is a declarator for an array of unknown bound (looking through
+ /// parentheses).
+ bool isArrayOfUnknownBound() const {
+ for (unsigned i = 0, i_end = DeclTypeInfo.size(); i < i_end; ++i) {
+ switch (DeclTypeInfo[i].Kind) {
+ case DeclaratorChunk::Paren:
+ continue;
+ case DeclaratorChunk::Function:
+ case DeclaratorChunk::Pointer:
+ case DeclaratorChunk::Reference:
+ case DeclaratorChunk::BlockPointer:
+ case DeclaratorChunk::MemberPointer:
+ return false;
+ case DeclaratorChunk::Array:
+ return !DeclTypeInfo[i].Arr.NumElts;
+ }
+ llvm_unreachable("Invalid type chunk");
+ return false;
+ }
+ return false;
+ }
+
/// isFunctionDeclarator - This method returns true if the declarator
/// is a function declarator (looking through parentheses).
/// If true is returned, then the reference type parameter idx is
diff --git a/include/clang/Sema/Initialization.h b/include/clang/Sema/Initialization.h
index e83e5c0..5dc4438 100644
--- a/include/clang/Sema/Initialization.h
+++ b/include/clang/Sema/Initialization.h
@@ -101,7 +101,8 @@ private:
/// the temporary is being created.
unsigned Location;
- /// \brief Whether the
+ /// \brief Whether the entity being initialized may end up using the
+ /// named return value optimization (NRVO).
bool NRVO;
} LocAndNRVO;
@@ -436,48 +437,21 @@ public:
class InitializationSequence {
public:
/// \brief Describes the kind of initialization sequence computed.
- ///
- /// FIXME: Much of this information is in the initialization steps... why is
- /// it duplicated here?
enum SequenceKind {
/// \brief A failed initialization sequence. The failure kind tells what
/// happened.
FailedSequence = 0,
-
+
/// \brief A dependent initialization, which could not be
/// type-checked due to the presence of dependent types or
- /// dependently-type expressions.
+ /// dependently-typed expressions.
DependentSequence,
- /// \brief A user-defined conversion sequence.
- UserDefinedConversion,
-
- /// \brief A constructor call.
- ConstructorInitialization,
-
- /// \brief A reference binding.
- ReferenceBinding,
-
- /// \brief List initialization
- ListInitialization,
-
- /// \brief Zero-initialization.
- ZeroInitialization,
-
- /// \brief No initialization required.
- NoInitialization,
-
- /// \brief Standard conversion sequence.
- StandardConversion,
-
- /// \brief C conversion sequence.
- CAssignment,
+ /// \brief A normal sequence.
+ NormalSequence,
- /// \brief String initialization
- StringInit,
-
- /// \brief Array initialization from another array (GNU C extension).
- ArrayInit
+ /// \brief A reference binding.
+ ReferenceBinding // FIXME: Still looks redundant, but complicated.
};
/// \brief Describes the kind of a particular step in an initialization
@@ -697,7 +671,10 @@ public:
void setSequenceKind(enum SequenceKind SK) { SequenceKind = SK; }
/// \brief Determine whether the initialization sequence is valid.
- operator bool() const { return SequenceKind != FailedSequence; }
+ operator bool() const { return !Failed(); }
+
+ /// \brief Determine whether the initialization sequence is invalid.
+ bool Failed() const { return SequenceKind == FailedSequence; }
typedef llvm::SmallVector<Step, 4>::const_iterator step_iterator;
step_iterator step_begin() const { return Steps.begin(); }
@@ -821,7 +798,7 @@ public:
/// \brief Determine why initialization failed.
FailureKind getFailureKind() const {
- assert(getKind() == FailedSequence && "Not an initialization failure!");
+ assert(Failed() && "Not an initialization failure!");
return Failure;
}
diff --git a/include/clang/Sema/Lookup.h b/include/clang/Sema/Lookup.h
index 400a7cc..dceed4e 100644
--- a/include/clang/Sema/Lookup.h
+++ b/include/clang/Sema/Lookup.h
@@ -282,6 +282,18 @@ public:
return NamingClass != 0;
}
+ /// \brief Set whether the name lookup is triggered by a
+ /// using declaration.
+ void setUsingDeclaration(bool U) {
+ UsingDeclaration = U;
+ }
+
+ /// \brief Returns whether the name lookup is triggered by a
+ /// using declaration.
+ bool isUsingDeclaration() const {
+ return UsingDeclaration;
+ }
+
/// \brief Returns the 'naming class' for this lookup, i.e. the
/// class which was looked into to find these results.
///
@@ -603,6 +615,10 @@ private:
bool HideTags;
bool Diagnose;
+
+ /// \brief True if the lookup is triggered by a using declaration.
+ /// Necessary to handle a MSVC bug.
+ bool UsingDeclaration;
};
/// \brief Consumes visible declarations found when searching for
diff --git a/include/clang/Sema/Overload.h b/include/clang/Sema/Overload.h
index e196e83..55931f2 100644
--- a/include/clang/Sema/Overload.h
+++ b/include/clang/Sema/Overload.h
@@ -202,8 +202,7 @@ namespace clang {
void setAsIdentityConversion();
bool isIdentityConversion() const {
- return First == ICK_Identity && Second == ICK_Identity &&
- Third == ICK_Identity;
+ return Second == ICK_Identity && Third == ICK_Identity;
}
ImplicitConversionRank getRank() const;
diff --git a/include/clang/Sema/Scope.h b/include/clang/Sema/Scope.h
index 6588a1d..7514633 100644
--- a/include/clang/Sema/Scope.h
+++ b/include/clang/Sema/Scope.h
@@ -79,7 +79,12 @@ public:
ObjCMethodScope = 0x400,
/// SwitchScope - This is a scope that corresponds to a switch statement.
- SwitchScope = 0x800
+ SwitchScope = 0x800,
+
+ /// ThisScope - This is the scope of a struct/union/class definition,
+ /// outside of any member function definition, where 'this' is nonetheless
+ /// usable.
+ ThisScope = 0x1000
};
private:
/// The parent scope for this scope. This is null for the translation-unit
diff --git a/include/clang/Sema/Sema.h b/include/clang/Sema/Sema.h
index 07a14d2..6dd0d3c 100644
--- a/include/clang/Sema/Sema.h
+++ b/include/clang/Sema/Sema.h
@@ -312,6 +312,17 @@ public:
/// and must warn if not used. Only contains the first declaration.
llvm::SmallVector<const DeclaratorDecl*, 4> UnusedFileScopedDecls;
+ /// \brief All the delegating constructors seen so far in the file, used for
+ /// cycle detection at the end of the TU.
+ llvm::SmallVector<CXXConstructorDecl*, 4> DelegatingCtorDecls;
+
+ /// \brief All the overriding destructors seen during a class definition
+ /// (there could be multiple due to nested classes) that had their exception
+ /// spec checks delayed, plus the overridden destructor.
+ llvm::SmallVector<std::pair<const CXXDestructorDecl*,
+ const CXXDestructorDecl*>, 2>
+ DelayedDestructorExceptionSpecChecks;
+
/// \brief Callback to the parser to parse templated functions when needed.
typedef void LateTemplateParserCB(void *P, const FunctionDecl *FD);
LateTemplateParserCB *LateTemplateParser;
@@ -589,6 +600,44 @@ public:
/// A stack of expression evaluation contexts.
llvm::SmallVector<ExpressionEvaluationContextRecord, 8> ExprEvalContexts;
+ /// SpecialMemberOverloadResult - The overloading result for a special member
+ /// function.
+ ///
+ /// This is basically a wrapper around PointerIntPair. The lowest bit of the
+ /// integer is used to determine whether we have a parameter qualification
+ /// match, the second-lowest is whether we had success in resolving the
+ /// overload to a unique non-deleted function.
+ ///
+ /// The ConstParamMatch bit represents whether, when looking up a copy
+ /// constructor or assignment operator, we found a potential copy
+ /// constructor/assignment operator whose first parameter is const-qualified.
+ /// This is used for determining parameter types of other objects and is
+ /// utterly meaningless on other types of special members.
+ class SpecialMemberOverloadResult : public llvm::FastFoldingSetNode {
+ llvm::PointerIntPair<CXXMethodDecl*, 2> Pair;
+ public:
+ SpecialMemberOverloadResult(const llvm::FoldingSetNodeID &ID)
+ : FastFoldingSetNode(ID)
+ {}
+
+ CXXMethodDecl *getMethod() const { return Pair.getPointer(); }
+ void setMethod(CXXMethodDecl *MD) { Pair.setPointer(MD); }
+
+ bool hasSuccess() const { return Pair.getInt() & 0x1; }
+ void setSuccess(bool B) {
+ Pair.setInt(unsigned(B) | hasConstParamMatch() << 1);
+ }
+
+ bool hasConstParamMatch() const { return Pair.getInt() & 0x2; }
+ void setConstParamMatch(bool B) {
+ Pair.setInt(B << 1 | unsigned(hasSuccess()));
+ }
+ };
+
+ /// \brief A cache of special member function overload resolution results
+ /// for C++ records.
+ llvm::FoldingSet<SpecialMemberOverloadResult> SpecialMemberCache;
+
/// \brief Whether the code handled by Sema should be considered a
/// complete translation unit or not.
///
@@ -704,6 +753,8 @@ public:
void ActOnEndOfTranslationUnit();
+ void CheckDelegatingCtorCycles();
+
Scope *getScopeForContext(DeclContext *Ctx);
void PushFunctionScope();
@@ -795,12 +846,19 @@ public:
const PartialDiagnostic &PD);
bool RequireCompleteType(SourceLocation Loc, QualType T,
unsigned DiagID);
+ bool RequireCompleteExprType(Expr *E, const PartialDiagnostic &PD,
+ std::pair<SourceLocation,
+ PartialDiagnostic> Note);
+
QualType getElaboratedType(ElaboratedTypeKeyword Keyword,
const CXXScopeSpec &SS, QualType T);
QualType BuildTypeofExprType(Expr *E, SourceLocation Loc);
QualType BuildDecltypeType(Expr *E, SourceLocation Loc);
+ QualType BuildUnaryTransformType(QualType BaseType,
+ UnaryTransformType::UTTKind UKind,
+ SourceLocation Loc);
//===--------------------------------------------------------------------===//
// Symbol table / Decl tracking callbacks: SemaDecl.cpp.
@@ -925,7 +983,8 @@ public:
SourceLocation NameLoc,
const Token &NextToken);
- Decl *ActOnDeclarator(Scope *S, Declarator &D);
+ Decl *ActOnDeclarator(Scope *S, Declarator &D,
+ bool IsFunctionDefintion = false);
Decl *HandleDeclarator(Scope *S, Declarator &D,
MultiTemplateParamsArg TemplateParameterLists,
@@ -938,6 +997,7 @@ public:
void CheckShadow(Scope *S, VarDecl *D, const LookupResult& R);
void CheckShadow(Scope *S, VarDecl *D);
void CheckCastAlign(Expr *Op, QualType T, SourceRange TRange);
+ void CheckTypedefForVariablyModifiedType(Scope *S, TypedefNameDecl *D);
NamedDecl* ActOnTypedefDeclarator(Scope* S, Declarator& D, DeclContext* DC,
QualType R, TypeSourceInfo *TInfo,
LookupResult &Previous, bool &Redeclaration);
@@ -988,6 +1048,7 @@ public:
void ActOnInitializerError(Decl *Dcl);
void ActOnCXXForRangeDecl(Decl *D);
void SetDeclDeleted(Decl *dcl, SourceLocation DelLoc);
+ void SetDeclDefaulted(Decl *dcl, SourceLocation DefaultLoc);
void FinalizeDeclaration(Decl *D);
DeclGroupPtrTy FinalizeDeclaratorGroup(Scope *S, const DeclSpec &DS,
Decl **Group,
@@ -1026,10 +1087,11 @@ public:
void ActOnPopScope(SourceLocation Loc, Scope *S);
void ActOnTranslationUnitScope(Scope *S);
- /// ParsedFreeStandingDeclSpec - This method is invoked when a declspec with
- /// no declarator (e.g. "struct foo;") is parsed.
Decl *ParsedFreeStandingDeclSpec(Scope *S, AccessSpecifier AS,
DeclSpec &DS);
+ Decl *ParsedFreeStandingDeclSpec(Scope *S, AccessSpecifier AS,
+ DeclSpec &DS,
+ MultiTemplateParamsArg TemplateParams);
StmtResult ActOnVlaStmt(const DeclSpec &DS);
@@ -1041,7 +1103,7 @@ public:
RecordDecl *Record);
bool isAcceptableTagRedeclaration(const TagDecl *Previous,
- TagTypeKind NewTag,
+ TagTypeKind NewTag, bool isDefinition,
SourceLocation NewTagLoc,
const IdentifierInfo &Name);
@@ -1082,23 +1144,25 @@ public:
Declarator &D, Expr *BitfieldWidth);
FieldDecl *HandleField(Scope *S, RecordDecl *TagD, SourceLocation DeclStart,
- Declarator &D, Expr *BitfieldWidth,
+ Declarator &D, Expr *BitfieldWidth, bool HasInit,
AccessSpecifier AS);
FieldDecl *CheckFieldDecl(DeclarationName Name, QualType T,
TypeSourceInfo *TInfo,
RecordDecl *Record, SourceLocation Loc,
- bool Mutable, Expr *BitfieldWidth,
+ bool Mutable, Expr *BitfieldWidth, bool HasInit,
SourceLocation TSSL,
AccessSpecifier AS, NamedDecl *PrevDecl,
Declarator *D = 0);
enum CXXSpecialMember {
- CXXInvalid = -1,
- CXXConstructor = 0,
- CXXCopyConstructor = 1,
- CXXCopyAssignment = 2,
- CXXDestructor = 3
+ CXXDefaultConstructor,
+ CXXCopyConstructor,
+ CXXMoveConstructor,
+ CXXCopyAssignment,
+ CXXMoveAssignment,
+ CXXDestructor,
+ CXXInvalid
};
bool CheckNontrivialField(FieldDecl *FD);
void DiagnoseNontrivial(const RecordType* Record, CXXSpecialMember mem);
@@ -1283,6 +1347,8 @@ public:
QualType ResultType,
Expr *Value);
+ bool CanPerformCopyInitialization(const InitializedEntity &Entity,
+ ExprResult Init);
ExprResult PerformCopyInitialization(const InitializedEntity &Entity,
SourceLocation EqualLoc,
ExprResult Init);
@@ -1566,6 +1632,14 @@ public:
private:
bool CppLookupName(LookupResult &R, Scope *S);
+ SpecialMemberOverloadResult *LookupSpecialMember(CXXRecordDecl *D,
+ CXXSpecialMember SM,
+ bool ConstArg,
+ bool VolatileArg,
+ bool RValueThis,
+ bool ConstThis,
+ bool VolatileThis);
+
public:
/// \brief Look up a name, looking for a single declaration. Return
/// null if the results were absent, ambiguous, or overloaded.
@@ -1594,6 +1668,10 @@ public:
SourceLocation GnuLabelLoc = SourceLocation());
DeclContextLookupResult LookupConstructors(CXXRecordDecl *Class);
+ CXXConstructorDecl *LookupDefaultConstructor(CXXRecordDecl *Class);
+ CXXConstructorDecl *LookupCopyConstructor(CXXRecordDecl *Class,
+ unsigned Quals,
+ bool *ConstParam = 0);
CXXDestructorDecl *LookupDestructor(CXXRecordDecl *Class);
void ArgumentDependentLookup(DeclarationName Name, bool Operator,
@@ -1645,6 +1723,10 @@ public:
AssociatedNamespaceSet &AssociatedNamespaces,
AssociatedClassSet &AssociatedClasses);
+ void FilterLookupForScope(LookupResult &R, DeclContext *Ctx, Scope *S,
+ bool ConsiderLinkage,
+ bool ExplicitInstantiationOrSpecialization);
+
bool DiagnoseAmbiguousLookup(LookupResult &Result);
//@}
@@ -2067,7 +2149,14 @@ public:
void MarkDeclarationReferenced(SourceLocation Loc, Decl *D);
void MarkDeclarationsReferencedInType(SourceLocation Loc, QualType T);
void MarkDeclarationsReferencedInExpr(Expr *E);
-
+
+ /// \brief Figure out if an expression could be turned into a call.
+ bool isExprCallable(const Expr &E, QualType &ZeroArgCallReturnTy,
+ UnresolvedSetImpl &NonTemplateOverloads);
+ /// \brief Give notes for a set of overloads.
+ void NoteOverloads(const UnresolvedSetImpl &Overloads,
+ const SourceLocation FinalNoteLoc);
+
/// \brief Conditionally issue a diagnostic based on the current
/// evaluation context.
///
@@ -2177,8 +2266,7 @@ public:
UnaryExprOrTypeTrait ExprKind,
SourceRange R);
ExprResult CreateUnaryExprOrTypeTraitExpr(Expr *E, SourceLocation OpLoc,
- UnaryExprOrTypeTrait ExprKind,
- SourceRange R);
+ UnaryExprOrTypeTrait ExprKind);
ExprResult
ActOnUnaryExprOrTypeTraitExpr(SourceLocation OpLoc,
UnaryExprOrTypeTrait ExprKind,
@@ -2186,8 +2274,9 @@ public:
const SourceRange &ArgRange);
ExprResult CheckPlaceholderExpr(Expr *E);
- bool CheckVecStepExpr(Expr *E, SourceLocation OpLoc, SourceRange R);
+ bool CheckVecStepExpr(Expr *E);
+ bool CheckUnaryExprOrTypeTraitOperand(Expr *E, UnaryExprOrTypeTrait ExprKind);
bool CheckUnaryExprOrTypeTraitOperand(QualType type, SourceLocation OpLoc,
SourceRange R,
UnaryExprOrTypeTrait ExprKind);
@@ -2364,6 +2453,8 @@ public:
bool CheckCaseExpression(Expr *expr);
+ bool CheckMicrosoftIfExistsSymbol(CXXScopeSpec &SS, UnqualifiedId &Name);
+
//===------------------------- "Block" Extension ------------------------===//
/// ActOnBlockStart - This callback is invoked when a block literal is
@@ -2383,6 +2474,13 @@ public:
ExprResult ActOnBlockStmtExpr(SourceLocation CaretLoc,
Stmt *Body, Scope *CurScope);
+ //===---------------------------- OpenCL Features -----------------------===//
+
+ /// __builtin_astype(...)
+ ExprResult ActOnAsTypeExpr(Expr *expr, ParsedType DestTy,
+ SourceLocation BuiltinLoc,
+ SourceLocation RParenLoc);
+
//===---------------------------- C++ Features --------------------------===//
// Act on C++ namespaces
@@ -2454,6 +2552,7 @@ public:
SourceLocation TypenameLoc);
Decl *ActOnAliasDeclaration(Scope *CurScope,
AccessSpecifier AS,
+ MultiTemplateParamsArg TemplateParams,
SourceLocation UsingLoc,
UnqualifiedId &Name,
TypeResult Type);
@@ -2502,6 +2601,111 @@ public:
/// constructed variable.
void FinalizeVarWithDestructor(VarDecl *VD, const RecordType *DeclInitType);
+ /// \brief Helper class that collects exception specifications for
+ /// implicitly-declared special member functions.
+ class ImplicitExceptionSpecification {
+ // Pointer to allow copying
+ ASTContext *Context;
+ // We order exception specifications thus:
+ // noexcept is the most restrictive, but is only used in C++0x.
+ // throw() comes next.
+ // Then a throw(collected exceptions)
+ // Finally no specification.
+ // throw(...) is used instead if any called function uses it.
+ //
+ // If this exception specification cannot be known yet (for instance,
+ // because this is the exception specification for a defaulted default
+ // constructor and we haven't finished parsing the deferred parts of the
+ // class yet), the C++0x standard does not specify how to behave. We
+ // record this as an 'unknown' exception specification, which overrules
+ // any other specification (even 'none', to keep this rule simple).
+ ExceptionSpecificationType ComputedEST;
+ llvm::SmallPtrSet<CanQualType, 4> ExceptionsSeen;
+ llvm::SmallVector<QualType, 4> Exceptions;
+
+ void ClearExceptions() {
+ ExceptionsSeen.clear();
+ Exceptions.clear();
+ }
+
+ public:
+ explicit ImplicitExceptionSpecification(ASTContext &Context)
+ : Context(&Context), ComputedEST(EST_BasicNoexcept) {
+ if (!Context.getLangOptions().CPlusPlus0x)
+ ComputedEST = EST_DynamicNone;
+ }
+
+ /// \brief Get the computed exception specification type.
+ ExceptionSpecificationType getExceptionSpecType() const {
+ assert(ComputedEST != EST_ComputedNoexcept &&
+ "noexcept(expr) should not be a possible result");
+ return ComputedEST;
+ }
+
+ /// \brief The number of exceptions in the exception specification.
+ unsigned size() const { return Exceptions.size(); }
+
+ /// \brief The set of exceptions in the exception specification.
+ const QualType *data() const { return Exceptions.data(); }
+
+ /// \brief Integrate another called method into the collected data.
+ void CalledDecl(CXXMethodDecl *Method);
+
+ /// \brief Integrate an invoked expression into the collected data.
+ void CalledExpr(Expr *E);
+
+ /// \brief Specify that the exception specification can't be detemined yet.
+ void SetDelayed() {
+ ClearExceptions();
+ ComputedEST = EST_Delayed;
+ }
+
+ FunctionProtoType::ExtProtoInfo getEPI() const {
+ FunctionProtoType::ExtProtoInfo EPI;
+ EPI.ExceptionSpecType = getExceptionSpecType();
+ EPI.NumExceptions = size();
+ EPI.Exceptions = data();
+ return EPI;
+ }
+ };
+
+ /// \brief Determine what sort of exception specification a defaulted
+ /// copy constructor of a class will have.
+ ImplicitExceptionSpecification
+ ComputeDefaultedDefaultCtorExceptionSpec(CXXRecordDecl *ClassDecl);
+
+ /// \brief Determine what sort of exception specification a defaulted
+ /// default constructor of a class will have, and whether the parameter
+ /// will be const.
+ std::pair<ImplicitExceptionSpecification, bool>
+ ComputeDefaultedCopyCtorExceptionSpecAndConst(CXXRecordDecl *ClassDecl);
+
+ /// \brief Determine what sort of exception specification a defautled
+ /// copy assignment operator of a class will have, and whether the
+ /// parameter will be const.
+ std::pair<ImplicitExceptionSpecification, bool>
+ ComputeDefaultedCopyAssignmentExceptionSpecAndConst(CXXRecordDecl *ClassDecl);
+
+ /// \brief Determine what sort of exception specification a defaulted
+ /// destructor of a class will have.
+ ImplicitExceptionSpecification
+ ComputeDefaultedDtorExceptionSpec(CXXRecordDecl *ClassDecl);
+
+ /// \brief Determine if a defaulted default constructor ought to be
+ /// deleted.
+ bool ShouldDeleteDefaultConstructor(CXXConstructorDecl *CD);
+
+ /// \brief Determine if a defaulted copy constructor ought to be
+ /// deleted.
+ bool ShouldDeleteCopyConstructor(CXXConstructorDecl *CD);
+
+ /// \brief Determine if a defaulted copy assignment operator ought to be
+ /// deleted.
+ bool ShouldDeleteCopyAssignmentOperator(CXXMethodDecl *MD);
+
+ /// \brief Determine if a defaulted destructor ought to be deleted.
+ bool ShouldDeleteDestructor(CXXDestructorDecl *DD);
+
/// \brief Declare the implicit default constructor for the given class.
///
/// \param ClassDecl The class declaration into which the implicit
@@ -2529,6 +2733,13 @@ public:
void DefineImplicitDestructor(SourceLocation CurrentLocation,
CXXDestructorDecl *Destructor);
+ /// \brief Build an exception spec for destructors that don't have one.
+ ///
+ /// C++11 says that user-defined destructors with no exception spec get one
+ /// that looks as if the destructor was implicitly declared.
+ void AdjustDestructorExceptionSpec(CXXRecordDecl *ClassDecl,
+ CXXDestructorDecl *Destructor);
+
/// \brief Declare all inherited constructors for the given class.
///
/// \param ClassDecl The class declaration into which the inherited
@@ -2549,8 +2760,7 @@ public:
/// DefineImplicitCopyConstructor - Checks for feasibility of
/// defining this constructor as the copy constructor.
void DefineImplicitCopyConstructor(SourceLocation CurrentLocation,
- CXXConstructorDecl *Constructor,
- unsigned TypeQuals);
+ CXXConstructorDecl *Constructor);
/// \brief Declare the implicit copy assignment operator for the given class.
///
@@ -2587,6 +2797,10 @@ public:
ParsedType ObjectType,
bool EnteringContext);
+ // Checks that reinterpret casts don't have undefined behavior.
+ void CheckCompatibleReinterpretCast(QualType SrcType, QualType DestType,
+ bool IsDereference, SourceRange Range);
+
/// ActOnCXXNamedCast - Parse {dynamic,static,reinterpret,const}_cast's.
ExprResult ActOnCXXNamedCast(SourceLocation OpLoc,
tok::TokenKind Kind,
@@ -2638,10 +2852,9 @@ public:
//// ActOnCXXThis - Parse 'this' pointer.
ExprResult ActOnCXXThis(SourceLocation loc);
- /// tryCaptureCXXThis - Try to capture a 'this' pointer. Returns a
- /// pointer to an instance method whose 'this' pointer is
- /// capturable, or null if this is not possible.
- CXXMethodDecl *tryCaptureCXXThis();
+ /// getAndCaptureCurrentThisType - Try to capture a 'this' pointer. Returns
+ /// the type of the 'this' pointer, or a null type if this is not possible.
+ QualType getAndCaptureCurrentThisType();
/// ActOnCXXBoolLiteral - Parse {true,false} literals.
ExprResult ActOnCXXBoolLiteral(SourceLocation OpLoc, tok::TokenKind Kind);
@@ -2699,14 +2912,16 @@ public:
bool FindAllocationOverload(SourceLocation StartLoc, SourceRange Range,
DeclarationName Name, Expr** Args,
unsigned NumArgs, DeclContext *Ctx,
- bool AllowMissing, FunctionDecl *&Operator);
+ bool AllowMissing, FunctionDecl *&Operator,
+ bool Diagnose = true);
void DeclareGlobalNewDelete();
void DeclareGlobalAllocationFunction(DeclarationName Name, QualType Return,
QualType Argument,
bool addMallocAttr = false);
bool FindDeallocationFunction(SourceLocation StartLoc, CXXRecordDecl *RD,
- DeclarationName Name, FunctionDecl* &Operator);
+ DeclarationName Name, FunctionDecl* &Operator,
+ bool Diagnose = true);
/// ActOnCXXDelete - Parsed a C++ 'delete' expression
ExprResult ActOnCXXDelete(SourceLocation StartLoc,
@@ -2985,7 +3200,7 @@ public:
Expr **Strings,
unsigned NumStrings);
- Expr *BuildObjCEncodeExpression(SourceLocation AtLoc,
+ ExprResult BuildObjCEncodeExpression(SourceLocation AtLoc,
TypeSourceInfo *EncodedTypeInfo,
SourceLocation RParenLoc);
ExprResult BuildCXXMemberCallExpr(Expr *Exp, NamedDecl *FoundDecl,
@@ -3038,8 +3253,10 @@ public:
Declarator &D,
MultiTemplateParamsArg TemplateParameterLists,
Expr *BitfieldWidth, const VirtSpecifiers &VS,
- Expr *Init, bool IsDefinition,
- bool Deleted = false);
+ Expr *Init, bool HasDeferredInit,
+ bool IsDefinition);
+ void ActOnCXXInClassMemberInitializer(Decl *VarDecl, SourceLocation EqualLoc,
+ Expr *Init);
MemInitResult ActOnMemInitializer(Decl *ConstructorD,
Scope *S,
@@ -3143,8 +3360,9 @@ public:
void ActOnStartDelayedMemberDeclarations(Scope *S, Decl *Record);
void ActOnStartDelayedCXXMethodDeclaration(Scope *S, Decl *Method);
void ActOnDelayedCXXMethodParameter(Scope *S, Decl *Param);
- void ActOnFinishDelayedCXXMethodDeclaration(Scope *S, Decl *Method);
void ActOnFinishDelayedMemberDeclarations(Scope *S, Decl *Record);
+ void ActOnFinishDelayedCXXMethodDeclaration(Scope *S, Decl *Method);
+ void ActOnFinishDelayedMemberInitializers(Decl *Record);
void MarkAsLateParsedTemplate(FunctionDecl *FD, bool Flag = true);
bool IsInsideALocalClassWithinATemplateFunction();
@@ -3170,6 +3388,12 @@ public:
StorageClass& SC);
Decl *ActOnConversionDeclarator(CXXConversionDecl *Conversion);
+ void CheckExplicitlyDefaultedMethods(CXXRecordDecl *Record);
+ void CheckExplicitlyDefaultedDefaultConstructor(CXXConstructorDecl *Ctor);
+ void CheckExplicitlyDefaultedCopyConstructor(CXXConstructorDecl *Ctor);
+ void CheckExplicitlyDefaultedCopyAssignment(CXXMethodDecl *Method);
+ void CheckExplicitlyDefaultedDestructor(CXXDestructorDecl *Dtor);
+
//===--------------------------------------------------------------------===//
// C++ Derived Classes
//
@@ -3257,12 +3481,17 @@ public:
AccessResult CheckAllocationAccess(SourceLocation OperatorLoc,
SourceRange PlacementRange,
CXXRecordDecl *NamingClass,
- DeclAccessPair FoundDecl);
+ DeclAccessPair FoundDecl,
+ bool Diagnose = true);
AccessResult CheckConstructorAccess(SourceLocation Loc,
CXXConstructorDecl *D,
const InitializedEntity &Entity,
AccessSpecifier Access,
bool IsCopyBindingRefToTemp = false);
+ AccessResult CheckConstructorAccess(SourceLocation Loc,
+ CXXConstructorDecl *D,
+ AccessSpecifier Access,
+ PartialDiagnostic PD);
AccessResult CheckDestructorAccess(SourceLocation Loc,
CXXDestructorDecl *Dtor,
const PartialDiagnostic &PDiag);
@@ -3394,7 +3623,8 @@ public:
TPC_FunctionTemplate,
TPC_ClassTemplateMember,
TPC_FriendFunctionTemplate,
- TPC_FriendFunctionTemplateDefinition
+ TPC_FriendFunctionTemplateDefinition,
+ TPC_TypeAliasTemplate
};
bool CheckTemplateParameterList(TemplateParameterList *NewParams,
@@ -3402,6 +3632,7 @@ public:
TemplateParamListContext TPC);
TemplateParameterList *
MatchTemplateParametersToScopeSpecifier(SourceLocation DeclStartLoc,
+ SourceLocation DeclLoc,
const CXXScopeSpec &SS,
TemplateParameterList **ParamLists,
unsigned NumParamLists,
@@ -4507,7 +4738,7 @@ public:
/// types, static variables, enumerators, etc.
std::deque<PendingImplicitInstantiation> PendingLocalImplicitInstantiations;
- bool PerformPendingInstantiations(bool LocalOnly = false);
+ void PerformPendingInstantiations(bool LocalOnly = false);
TypeSourceInfo *SubstType(TypeSourceInfo *T,
const MultiLevelTemplateArgumentList &TemplateArgs,
@@ -4644,7 +4875,7 @@ public:
IdentifierInfo *AliasName, SourceLocation AliasLocation,
IdentifierInfo *ClassName, SourceLocation ClassLocation);
- void CheckForwardProtocolDeclarationForCircularDependency(
+ bool CheckForwardProtocolDeclarationForCircularDependency(
IdentifierInfo *PName,
SourceLocation &PLoc, SourceLocation PrevLoc,
const ObjCList<ObjCProtocolDecl> &PList);
@@ -4769,7 +5000,7 @@ public:
SourceLocation EndLoc, // location of the ; or {.
tok::TokenKind MethodType,
Decl *ClassDecl, ObjCDeclSpec &ReturnQT, ParsedType ReturnType,
- Selector Sel,
+ SourceLocation SelectorStartLoc, Selector Sel,
// optional arguments. The number of types/arguments is obtained
// from the Sel.getNumArgs().
ObjCArgInfo *ArgInfo,
@@ -4867,7 +5098,18 @@ public:
SourceLocation RBracLoc,
MultiExprArg Args);
-
+ /// \brief Check whether the given new method is a valid override of the
+ /// given overridden method, and set any properties that should be inherited.
+ ///
+ /// \returns True if an error occurred.
+ bool CheckObjCMethodOverride(ObjCMethodDecl *NewMethod,
+ const ObjCMethodDecl *Overridden,
+ bool IsImplementation);
+
+ /// \brief Check whether the given method overrides any methods in its class,
+ /// calling \c CheckObjCMethodOverride for each overridden method.
+ bool CheckObjCMethodOverrides(ObjCMethodDecl *NewMethod, DeclContext *DC);
+
enum PragmaOptionsAlignKind {
POAK_Native, // #pragma options align=native
POAK_Natural, // #pragma options align=natural
@@ -5289,11 +5531,24 @@ public:
/// \param Method - May be null.
/// \param [out] ReturnType - The return type of the send.
/// \return true iff there were any incompatible types.
- bool CheckMessageArgumentTypes(Expr **Args, unsigned NumArgs, Selector Sel,
+ bool CheckMessageArgumentTypes(QualType ReceiverType,
+ Expr **Args, unsigned NumArgs, Selector Sel,
ObjCMethodDecl *Method, bool isClassMessage,
+ bool isSuperMessage,
SourceLocation lbrac, SourceLocation rbrac,
QualType &ReturnType, ExprValueKind &VK);
+ /// \brief Determine the result of a message send expression based on
+ /// the type of the receiver, the method expected to receive the message,
+ /// and the form of the message send.
+ QualType getMessageSendResultType(QualType ReceiverType,
+ ObjCMethodDecl *Method,
+ bool isClassMessage, bool isSuperMessage);
+
+ /// \brief If the given expression involves a message send to a method
+ /// with a related result type, emit a note describing what happened.
+ void EmitRelatedResultTypeNote(const Expr *E);
+
/// CheckBooleanCondition - Diagnose problems involving the use of
/// the given expression as a boolean condition (e.g. in an if
/// statement). Also performs the standard function and array
@@ -5547,7 +5802,8 @@ private:
unsigned format_idx, unsigned firstDataArg,
bool isPrintf);
- void CheckMemsetArguments(const CallExpr *Call);
+ void CheckMemsetcpymoveArguments(const CallExpr *Call,
+ const IdentifierInfo *FnName);
void CheckReturnStackAddr(Expr *RetValExp, QualType lhsType,
SourceLocation ReturnLoc);
diff --git a/include/clang/Sema/Template.h b/include/clang/Sema/Template.h
index 4d97f9b..a257772 100644
--- a/include/clang/Sema/Template.h
+++ b/include/clang/Sema/Template.h
@@ -335,9 +335,9 @@ namespace clang {
Decl *VisitLabelDecl(LabelDecl *D);
Decl *VisitNamespaceDecl(NamespaceDecl *D);
Decl *VisitNamespaceAliasDecl(NamespaceAliasDecl *D);
- Decl *VisitTypedefNameDecl(TypedefNameDecl *D, bool IsTypeAlias);
Decl *VisitTypedefDecl(TypedefDecl *D);
Decl *VisitTypeAliasDecl(TypeAliasDecl *D);
+ Decl *VisitTypeAliasTemplateDecl(TypeAliasTemplateDecl *D);
Decl *VisitVarDecl(VarDecl *D);
Decl *VisitAccessSpecDecl(AccessSpecDecl *D);
Decl *VisitFieldDecl(FieldDecl *D);
@@ -415,6 +415,7 @@ namespace clang {
bool SubstQualifier(const TagDecl *OldDecl,
TagDecl *NewDecl);
+ Decl *InstantiateTypedefNameDecl(TypedefNameDecl *D, bool IsTypeAlias);
ClassTemplatePartialSpecializationDecl *
InstantiateClassTemplatePartialSpecialization(
ClassTemplateDecl *ClassTemplate,
diff --git a/include/clang/Serialization/ASTBitCodes.h b/include/clang/Serialization/ASTBitCodes.h
index 1cfd458..c881b23 100644
--- a/include/clang/Serialization/ASTBitCodes.h
+++ b/include/clang/Serialization/ASTBitCodes.h
@@ -279,7 +279,9 @@ namespace clang {
/// generate the AST file.
ORIGINAL_FILE_NAME = 19,
- /// Record #20 intentionally left blank.
+ /// \brief Record code for the file ID of the original file used to
+ /// generate the AST file.
+ ORIGINAL_FILE_ID = 20,
/// \brief Record code for the version control branch and revision
/// information of the compiler used to build this AST file.
@@ -362,7 +364,15 @@ namespace clang {
FP_PRAGMA_OPTIONS = 42,
/// \brief Record code for enabled OpenCL extensions.
- OPENCL_EXTENSIONS = 43
+ OPENCL_EXTENSIONS = 43,
+
+ /// \brief The list of delegating constructor declarations.
+ DELEGATING_CTORS = 44,
+
+ /// \brief Record code for the table of offsets into the block
+ /// of file source-location information.
+ FILE_SOURCE_LOCATION_OFFSETS = 45
+
};
/// \brief Record types used within a source manager block.
@@ -504,6 +514,9 @@ namespace clang {
/// NUM_PREDEF_TYPE_IDs.
const unsigned NUM_PREDEF_TYPE_IDS = 100;
+ /// \brief The number of allowed abbreviations in bits
+ const unsigned NUM_ALLOWED_ABBREVS_SIZE = 4;
+
/// \brief Record codes for each kind of type.
///
/// These constants describe the type records that can occur within a
@@ -584,7 +597,9 @@ namespace clang {
/// \brief A SubstTemplateTypeParmPackType record.
TYPE_SUBST_TEMPLATE_TYPE_PARM_PACK = 37,
/// \brief A AutoType record.
- TYPE_AUTO = 38
+ TYPE_AUTO = 38,
+ /// \brief A UnaryTransformType record.
+ TYPE_UNARY_TRANSFORM = 39
};
/// \brief The type IDs for special types constructed by semantic
@@ -758,6 +773,8 @@ namespace clang {
DECL_NON_TYPE_TEMPLATE_PARM,
/// \brief A TemplateTemplateParmDecl record.
DECL_TEMPLATE_TEMPLATE_PARM,
+ /// \brief A TypeAliasTemplateDecl record.
+ DECL_TYPE_ALIAS_TEMPLATE,
/// \brief A StaticAssertDecl record.
DECL_STATIC_ASSERT,
/// \brief A record containing CXXBaseSpecifiers.
@@ -986,7 +1003,10 @@ namespace clang {
// CUDA
- EXPR_CUDA_KERNEL_CALL // CUDAKernelCallExpr
+ EXPR_CUDA_KERNEL_CALL, // CUDAKernelCallExpr
+
+ // OpenCL
+ EXPR_ASTYPE // An AsTypeExpr record.
};
/// \brief The kinds of designators that can occur in a
@@ -1003,6 +1023,15 @@ namespace clang {
DESIG_ARRAY_RANGE = 3
};
+ /// \brief The different kinds of data that can occur in a
+ /// CtorInitializer.
+ enum CtorInitializerType {
+ CTOR_INITIALIZER_BASE,
+ CTOR_INITIALIZER_DELEGATING,
+ CTOR_INITIALIZER_MEMBER,
+ CTOR_INITIALIZER_INDIRECT_MEMBER
+ };
+
/// @}
}
} // end namespace clang
diff --git a/include/clang/Serialization/ASTReader.h b/include/clang/Serialization/ASTReader.h
index da018ab..8923e2a 100644
--- a/include/clang/Serialization/ASTReader.h
+++ b/include/clang/Serialization/ASTReader.h
@@ -54,6 +54,7 @@ class Decl;
class DeclContext;
class NestedNameSpecifier;
class CXXBaseSpecifier;
+class CXXConstructorDecl;
class CXXCtorInitializer;
class GotoStmt;
class MacroDefinition;
@@ -256,6 +257,13 @@ private:
/// AST file.
const uint32_t *SLocOffsets;
+ /// \brief The number of source location file entries in this AST file.
+ unsigned LocalNumSLocFileEntries;
+
+ /// \brief Offsets for all of the source location file entries in the
+ /// AST file.
+ const uint32_t *SLocFileOffsets;
+
/// \brief The entire size of this module's source location offset range.
unsigned LocalSLocSize;
@@ -564,6 +572,10 @@ private:
/// generating warnings.
llvm::SmallVector<uint64_t, 16> UnusedFileScopedDecls;
+ /// \brief A list of all the delegating constructors we've seen, to diagnose
+ /// cycles.
+ llvm::SmallVector<uint64_t, 4> DelegatingCtorDecls;
+
/// \brief A snapshot of Sema's weak undeclared identifier tracking, for
/// generating warnings.
llvm::SmallVector<uint64_t, 64> WeakUndeclaredIdentifiers;
@@ -626,6 +638,10 @@ private:
/// AST file.
std::string ActualOriginalFileName;
+ /// \brief The file ID for the original file that was used to build the
+ /// primary AST file.
+ FileID OriginalFileID;
+
/// \brief The directory that the PCH was originally created in. Used to
/// allow resolving headers even after headers+PCH was moved to a new path.
std::string OriginalDir;
@@ -780,6 +796,10 @@ private:
/// \brief Reads a statement from the specified cursor.
Stmt *ReadStmtFromStream(PerFileData &F);
+ /// \brief Get a FileEntry out of stored-in-PCH filename, making sure we take
+ /// into account all the necessary relocations.
+ const FileEntry *getFileEntry(llvm::StringRef filename);
+
void MaybeAddSystemRootToFilename(std::string &Filename);
ASTReadResult ReadASTCore(llvm::StringRef FileName, ASTFileType Type);
@@ -879,6 +899,10 @@ public:
/// name.
ASTReadResult ReadAST(const std::string &FileName, ASTFileType Type);
+ /// \brief Checks that no file that is stored in PCH is out-of-sync with
+ /// the actual file in the file system.
+ ASTReadResult validateFileEntries();
+
/// \brief Set the AST callbacks listener.
void setListener(ASTReaderListener *listener) {
Listener.reset(listener);
diff --git a/include/clang/Serialization/ASTWriter.h b/include/clang/Serialization/ASTWriter.h
index 1a79b31..78a63ab 100644
--- a/include/clang/Serialization/ASTWriter.h
+++ b/include/clang/Serialization/ASTWriter.h
@@ -338,10 +338,20 @@ private:
void WriteFPPragmaOptions(const FPOptions &Opts);
void WriteOpenCLExtensions(Sema &SemaRef);
- unsigned ParmVarDeclAbbrev;
+ unsigned DeclParmVarAbbrev;
unsigned DeclContextLexicalAbbrev;
unsigned DeclContextVisibleLookupAbbrev;
unsigned UpdateVisibleAbbrev;
+ unsigned DeclRefExprAbbrev;
+ unsigned CharacterLiteralAbbrev;
+ unsigned DeclRecordAbbrev;
+ unsigned IntegerLiteralAbbrev;
+ unsigned DeclTypedefAbbrev;
+ unsigned DeclVarAbbrev;
+ unsigned DeclFieldAbbrev;
+ unsigned DeclEnumAbbrev;
+ unsigned DeclObjCIvarAbbrev;
+
void WriteDeclsBlockAbbrevs();
void WriteDecl(ASTContext &Context, Decl *D);
@@ -568,7 +578,16 @@ public:
/// \brief Retrieve the ID for the given opaque value expression.
unsigned getOpaqueValueID(OpaqueValueExpr *e);
- unsigned getParmVarDeclAbbrev() const { return ParmVarDeclAbbrev; }
+ unsigned getDeclParmVarAbbrev() const { return DeclParmVarAbbrev; }
+ unsigned getDeclRefExprAbbrev() const { return DeclRefExprAbbrev; }
+ unsigned getCharacterLiteralAbbrev() const { return CharacterLiteralAbbrev; }
+ unsigned getDeclRecordAbbrev() const { return DeclRecordAbbrev; }
+ unsigned getIntegerLiteralAbbrev() const { return IntegerLiteralAbbrev; }
+ unsigned getDeclTypedefAbbrev() const { return DeclTypedefAbbrev; }
+ unsigned getDeclVarAbbrev() const { return DeclVarAbbrev; }
+ unsigned getDeclFieldAbbrev() const { return DeclFieldAbbrev; }
+ unsigned getDeclEnumAbbrev() const { return DeclEnumAbbrev; }
+ unsigned getDeclObjCIvarAbbrev() const { return DeclObjCIvarAbbrev; }
bool hasChain() const { return Chain; }
diff --git a/include/clang/StaticAnalyzer/Core/Checker.h b/include/clang/StaticAnalyzer/Core/Checker.h
index 8c2ffc6..eb38bd8 100644
--- a/include/clang/StaticAnalyzer/Core/Checker.h
+++ b/include/clang/StaticAnalyzer/Core/Checker.h
@@ -63,6 +63,24 @@ public:
}
};
+class EndOfTranslationUnit {
+ template <typename CHECKER>
+ static void _checkEndOfTranslationUnit(void *checker,
+ const TranslationUnitDecl *TU,
+ AnalysisManager& mgr,
+ BugReporter &BR) {
+ ((const CHECKER *)checker)->checkEndOfTranslationUnit(TU, mgr, BR);
+ }
+
+public:
+ template <typename CHECKER>
+ static void _register(CHECKER *checker, CheckerManager &mgr){
+ mgr._registerForEndOfTranslationUnit(
+ CheckerManager::CheckEndOfTranslationUnit(checker,
+ _checkEndOfTranslationUnit<CHECKER>));
+ }
+};
+
template <typename STMT>
class PreStmt {
template <typename CHECKER>
@@ -240,9 +258,11 @@ public:
class RegionChanges {
template <typename CHECKER>
static const GRState *_checkRegionChanges(void *checker, const GRState *state,
+ const StoreManager::InvalidatedSymbols *invalidated,
const MemRegion * const *Begin,
const MemRegion * const *End) {
- return ((const CHECKER *)checker)->checkRegionChanges(state, Begin, End);
+ return ((const CHECKER *)checker)->checkRegionChanges(state, invalidated,
+ Begin, End);
}
template <typename CHECKER>
static bool _wantsRegionChangeUpdate(void *checker, const GRState *state) {
diff --git a/include/clang/StaticAnalyzer/Core/CheckerManager.h b/include/clang/StaticAnalyzer/Core/CheckerManager.h
index 92ec038..45d38fb 100644
--- a/include/clang/StaticAnalyzer/Core/CheckerManager.h
+++ b/include/clang/StaticAnalyzer/Core/CheckerManager.h
@@ -18,6 +18,7 @@
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/FoldingSet.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/Store.h"
#include <vector>
namespace clang {
@@ -49,6 +50,18 @@ public:
template <typename T> class CheckerFn;
+template <typename RET, typename P1, typename P2, typename P3, typename P4>
+class CheckerFn<RET(P1, P2, P3, P4)> {
+ typedef RET (*Func)(void *, P1, P2, P3, P4);
+ Func Fn;
+public:
+ void *Checker;
+ CheckerFn(void *checker, Func fn) : Fn(fn), Checker(checker) { }
+ RET operator()(P1 p1, P2 p2, P3 p3, P4 p4) const {
+ return Fn(Checker, p1, p2, p3, p4);
+ }
+};
+
template <typename RET, typename P1, typename P2, typename P3>
class CheckerFn<RET(P1, P2, P3)> {
typedef RET (*Func)(void *, P1, P2, P3);
@@ -224,9 +237,11 @@ public:
bool wantsRegionChangeUpdate(const GRState *state);
/// \brief Run checkers for region changes.
- const GRState *runCheckersForRegionChanges(const GRState *state,
- const MemRegion * const *Begin,
- const MemRegion * const *End);
+ const GRState *
+ runCheckersForRegionChanges(const GRState *state,
+ const StoreManager::InvalidatedSymbols *invalidated,
+ const MemRegion * const *Begin,
+ const MemRegion * const *End);
/// \brief Run checkers for handling assumptions on symbolic values.
const GRState *runCheckersForEvalAssume(const GRState *state,
@@ -237,6 +252,11 @@ public:
const ExplodedNodeSet &Src,
const CallExpr *CE, ExprEngine &Eng,
GraphExpander *defaultEval = 0);
+
+ /// \brief Run checkers for the entire Translation Unit.
+ void runCheckersOnEndOfTranslationUnit(const TranslationUnitDecl* TU,
+ AnalysisManager &mgr,
+ BugReporter &BR);
//===----------------------------------------------------------------------===//
// Internal registration functions for AST traversing.
@@ -283,6 +303,7 @@ public:
typedef CheckerFn<void (const GRState *,SymbolReaper &)> CheckLiveSymbolsFunc;
typedef CheckerFn<const GRState * (const GRState *,
+ const StoreManager::InvalidatedSymbols *symbols,
const MemRegion * const *begin,
const MemRegion * const *end)>
CheckRegionChangesFunc;
@@ -296,6 +317,10 @@ public:
typedef CheckerFn<bool (const CallExpr *, CheckerContext &)>
EvalCallFunc;
+ typedef CheckerFn<void (const TranslationUnitDecl *,
+ AnalysisManager&, BugReporter &)>
+ CheckEndOfTranslationUnit;
+
typedef bool (*HandlesStmtFunc)(const Stmt *D);
void _registerForPreStmt(CheckStmtFunc checkfn,
HandlesStmtFunc isForStmtFn);
@@ -326,6 +351,8 @@ public:
void _registerForEvalCall(EvalCallFunc checkfn);
+ void _registerForEndOfTranslationUnit(CheckEndOfTranslationUnit checkfn);
+
//===----------------------------------------------------------------------===//
// Internal registration functions for events.
//===----------------------------------------------------------------------===//
@@ -446,6 +473,8 @@ private:
std::vector<EvalCallFunc> EvalCallCheckers;
+ std::vector<CheckEndOfTranslationUnit> EndOfTranslationUnitCheckers;
+
struct EventInfo {
llvm::SmallVector<CheckEventFunc, 4> Checkers;
bool HasDispatcher;
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/BasicValueFactory.h b/include/clang/StaticAnalyzer/Core/PathSensitive/BasicValueFactory.h
index 65fbfcc..69495be 100644
--- a/include/clang/StaticAnalyzer/Core/PathSensitive/BasicValueFactory.h
+++ b/include/clang/StaticAnalyzer/Core/PathSensitive/BasicValueFactory.h
@@ -108,7 +108,8 @@ public:
const llvm::APSInt &Convert(QualType T, const llvm::APSInt &From) {
assert(T->isIntegerType() || Loc::isLocType(T));
unsigned bitwidth = Ctx.getTypeSize(T);
- bool isUnsigned = T->isUnsignedIntegerType() || Loc::isLocType(T);
+ bool isUnsigned
+ = T->isUnsignedIntegerOrEnumerationType() || Loc::isLocType(T);
if (isUnsigned == From.isUnsigned() && bitwidth == From.getBitWidth())
return From;
@@ -131,13 +132,15 @@ public:
inline const llvm::APSInt& getMaxValue(QualType T) {
assert(T->isIntegerType() || Loc::isLocType(T));
- bool isUnsigned = T->isUnsignedIntegerType() || Loc::isLocType(T);
+ bool isUnsigned
+ = T->isUnsignedIntegerOrEnumerationType() || Loc::isLocType(T);
return getValue(llvm::APSInt::getMaxValue(Ctx.getTypeSize(T), isUnsigned));
}
inline const llvm::APSInt& getMinValue(QualType T) {
assert(T->isIntegerType() || Loc::isLocType(T));
- bool isUnsigned = T->isUnsignedIntegerType() || Loc::isLocType(T);
+ bool isUnsigned
+ = T->isUnsignedIntegerOrEnumerationType() || Loc::isLocType(T);
return getValue(llvm::APSInt::getMinValue(Ctx.getTypeSize(T), isUnsigned));
}
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h b/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h
index 8cd743f..d24036c 100644
--- a/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h
+++ b/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h
@@ -21,6 +21,7 @@
#include "clang/StaticAnalyzer/Core/PathSensitive/CoreEngine.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/GRState.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/TransferFuncs.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/ObjCMessage.h"
#include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h"
#include "clang/AST/Type.h"
#include "clang/AST/ExprObjC.h"
@@ -188,9 +189,11 @@ public:
/// processRegionChanges - Called by GRStateManager whenever a change is made
/// to the store. Used to update checkers that track region values.
- const GRState* processRegionChanges(const GRState *state,
- const MemRegion * const *Begin,
- const MemRegion * const *End);
+ const GRState *
+ processRegionChanges(const GRState *state,
+ const StoreManager::InvalidatedSymbols *invalidated,
+ const MemRegion * const *Begin,
+ const MemRegion * const *End);
virtual GRStateManager& getStateManager() { return StateMgr; }
@@ -458,6 +461,13 @@ private:
const void *tag, bool isLoad);
bool InlineCall(ExplodedNodeSet &Dst, const CallExpr *CE, ExplodedNode *Pred);
+
+
+public:
+ /// Returns true if calling the specific function or method would possibly
+ /// cause global variables to be invalidated.
+ bool doesInvalidateGlobals(const CallOrObjCMessage &callOrMessage) const;
+
};
} // end ento namespace
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/GRState.h b/include/clang/StaticAnalyzer/Core/PathSensitive/GRState.h
index a957c89..0d61d0e 100644
--- a/include/clang/StaticAnalyzer/Core/PathSensitive/GRState.h
+++ b/include/clang/StaticAnalyzer/Core/PathSensitive/GRState.h
@@ -368,6 +368,12 @@ private:
assert(refCount > 0);
--refCount;
}
+
+ const GRState *invalidateRegionsImpl(const MemRegion * const *Begin,
+ const MemRegion * const *End,
+ const Expr *E, unsigned BlockCount,
+ StoreManager::InvalidatedSymbols &IS,
+ bool invalidateGlobals) const;
};
class GRStateSet {
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/ObjCMessage.h b/include/clang/StaticAnalyzer/Core/PathSensitive/ObjCMessage.h
index 6d8fc89..734024c 100644
--- a/include/clang/StaticAnalyzer/Core/PathSensitive/ObjCMessage.h
+++ b/include/clang/StaticAnalyzer/Core/PathSensitive/ObjCMessage.h
@@ -187,6 +187,7 @@ public:
return CallE && isa<CXXMemberCallExpr>(CallE);
}
+ SVal getFunctionCallee() const;
SVal getCXXCallee() const;
unsigned getNumArgs() const {
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h b/include/clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h
index 0f9e56a..65eabea 100644
--- a/include/clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h
+++ b/include/clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h
@@ -172,7 +172,7 @@ public:
nonloc::ConcreteInt makeIntVal(const IntegerLiteral* integer) {
return nonloc::ConcreteInt(
BasicVals.getValue(integer->getValue(),
- integer->getType()->isUnsignedIntegerType()));
+ integer->getType()->isUnsignedIntegerOrEnumerationType()));
}
nonloc::ConcreteInt makeBoolVal(const CXXBoolLiteralExpr *boolean) {
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/Store.h b/include/clang/StaticAnalyzer/Core/PathSensitive/Store.h
index 21c6ae7..cdbdf64 100644
--- a/include/clang/StaticAnalyzer/Core/PathSensitive/Store.h
+++ b/include/clang/StaticAnalyzer/Core/PathSensitive/Store.h
@@ -188,7 +188,7 @@ public:
const MemRegion * const *Begin,
const MemRegion * const *End,
const Expr *E, unsigned Count,
- InvalidatedSymbols *IS,
+ InvalidatedSymbols &IS,
bool invalidateGlobals,
InvalidatedRegions *Regions) = 0;
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/SubEngine.h b/include/clang/StaticAnalyzer/Core/PathSensitive/SubEngine.h
index 3d6f9fa..1f6ea3d 100644
--- a/include/clang/StaticAnalyzer/Core/PathSensitive/SubEngine.h
+++ b/include/clang/StaticAnalyzer/Core/PathSensitive/SubEngine.h
@@ -15,6 +15,7 @@
#include "clang/Analysis/ProgramPoint.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/SVals.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/Store.h"
namespace clang {
@@ -95,13 +96,17 @@ public:
/// processRegionChanges - Called by GRStateManager whenever a change is made
/// to the store. Used to update checkers that track region values.
- virtual const GRState* processRegionChanges(const GRState* state,
- const MemRegion* const *Begin,
- const MemRegion* const *End) = 0;
+ virtual const GRState *
+ processRegionChanges(const GRState *state,
+ const StoreManager::InvalidatedSymbols *invalidated,
+ const MemRegion* const *Begin,
+ const MemRegion* const *End) = 0;
- inline const GRState* processRegionChange(const GRState* state,
- const MemRegion* MR) {
- return processRegionChanges(state, &MR, &MR+1);
+
+ inline const GRState *
+ processRegionChange(const GRState* state,
+ const MemRegion* MR) {
+ return processRegionChanges(state, 0, &MR, &MR+1);
}
/// Called by CoreEngine when the analysis worklist is either empty or the
diff --git a/include/clang/Tooling/Tooling.h b/include/clang/Tooling/Tooling.h
deleted file mode 100644
index 6ccccd0..0000000
--- a/include/clang/Tooling/Tooling.h
+++ /dev/null
@@ -1,81 +0,0 @@
-//===--- Tooling.h - Framework for standalone Clang tools -------*- C++ -*-===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-//
-// This file implements functions to run clang tools standalone instead
-// of running them as a plugin.
-//
-//===----------------------------------------------------------------------===//
-
-#ifndef LLVM_CLANG_TOOLING_TOOLING_H
-#define LLVM_CLANG_TOOLING_TOOLING_H
-
-#include "llvm/ADT/StringRef.h"
-#include <string>
-#include <vector>
-
-namespace clang {
-
-class FrontendAction;
-
-namespace tooling {
-
-/// \brief Runs (and deletes) the tool on 'Code' with the -fsynatx-only flag.
-///
-/// \param ToolAction The action to run over the code.
-/// \param Code C++ code.
-///
-/// \return - True if 'ToolAction' was successfully executed.
-bool RunSyntaxOnlyToolOnCode(
- clang::FrontendAction *ToolAction, llvm::StringRef Code);
-
-/// \brief Runs (and deletes) the tool with the given Clang flags.
-///
-/// \param ToolAction The action to run over the code.
-/// \param Argc The number of elements in Argv.
-/// \param Argv The command line arguments, including the path the binary
-/// was started with (Argv[0]).
-bool RunToolWithFlags(
- clang::FrontendAction* ToolAction, int Argc, char *Argv[]);
-
-/// \brief Converts a vector<string> into a vector<char*> suitable to pass
-/// to main-style functions taking (int Argc, char *Argv[]).
-std::vector<char*> CommandLineToArgv(const std::vector<std::string>* Command);
-
-/// \brief Specifies the working directory and command of a compilation.
-struct CompileCommand {
- /// \brief The working directory the command was executed from.
- std::string Directory;
-
- /// \brief The command line that was executed.
- std::vector<std::string> CommandLine;
-};
-
-/// \brief Looks up the compile command for 'FileName' in 'JsonDatabase'.
-///
-/// \param FileName The path to an input file for which we want the compile
-/// command line. If the 'JsonDatabase' was created by CMake, this must be
-/// an absolute path inside the CMake source directory which does not have
-/// symlinks resolved.
-///
-/// \param JsonDatabase A JSON formatted list of compile commands. This lookup
-/// command supports only a subset of the JSON standard as written by CMake.
-///
-/// \param ErrorMessage If non-empty, an error occurred and 'ErrorMessage' will
-/// be set to contain the error message. In this case CompileCommand will
-/// contain an empty directory and command line.
-///
-/// \see JsonCompileCommandLineDatabase
-CompileCommand FindCompileArgsInJsonDatabase(
- llvm::StringRef FileName, llvm::StringRef JsonDatabase,
- std::string &ErrorMessage);
-
-} // end namespace tooling
-} // end namespace clang
-
-#endif // LLVM_CLANG_TOOLING_TOOLING_H
diff --git a/lib/AST/APValue.cpp b/lib/AST/APValue.cpp
index 731d5e0..ebe99b1 100644
--- a/lib/AST/APValue.cpp
+++ b/lib/AST/APValue.cpp
@@ -18,12 +18,12 @@ using namespace clang;
namespace {
struct LV {
- Expr* Base;
+ const Expr* Base;
CharUnits Offset;
};
}
-APValue::APValue(Expr* B) : Kind(Uninitialized) {
+APValue::APValue(const Expr* B) : Kind(Uninitialized) {
MakeLValue(); setLValue(B, CharUnits::Zero());
}
@@ -118,7 +118,7 @@ void APValue::print(llvm::raw_ostream &OS) const {
}
}
-Expr* APValue::getLValueBase() const {
+const Expr* APValue::getLValueBase() const {
assert(isLValue() && "Invalid accessor");
return ((const LV*)(const void*)Data)->Base;
}
@@ -128,7 +128,7 @@ CharUnits APValue::getLValueOffset() const {
return ((const LV*)(const void*)Data)->Offset;
}
-void APValue::setLValue(Expr *B, const CharUnits &O) {
+void APValue::setLValue(const Expr *B, const CharUnits &O) {
assert(isLValue() && "Invalid accessor");
((LV*)(char*)Data)->Base = B;
((LV*)(char*)Data)->Offset = O;
diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp
index 8316ea6..9094aba 100644
--- a/lib/AST/ASTContext.cpp
+++ b/lib/AST/ASTContext.cpp
@@ -31,6 +31,7 @@
#include "llvm/Support/MathExtras.h"
#include "llvm/Support/raw_ostream.h"
#include "CXXABI.h"
+#include <map>
using namespace clang;
@@ -38,8 +39,12 @@ unsigned ASTContext::NumImplicitDefaultConstructors;
unsigned ASTContext::NumImplicitDefaultConstructorsDeclared;
unsigned ASTContext::NumImplicitCopyConstructors;
unsigned ASTContext::NumImplicitCopyConstructorsDeclared;
+unsigned ASTContext::NumImplicitMoveConstructors;
+unsigned ASTContext::NumImplicitMoveConstructorsDeclared;
unsigned ASTContext::NumImplicitCopyAssignmentOperators;
unsigned ASTContext::NumImplicitCopyAssignmentOperatorsDeclared;
+unsigned ASTContext::NumImplicitMoveAssignmentOperators;
+unsigned ASTContext::NumImplicitMoveAssignmentOperatorsDeclared;
unsigned ASTContext::NumImplicitDestructors;
unsigned ASTContext::NumImplicitDestructorsDeclared;
@@ -317,9 +322,17 @@ void ASTContext::PrintStats() const {
fprintf(stderr, " %u/%u implicit copy constructors created\n",
NumImplicitCopyConstructorsDeclared,
NumImplicitCopyConstructors);
+ if (getLangOptions().CPlusPlus)
+ fprintf(stderr, " %u/%u implicit move constructors created\n",
+ NumImplicitMoveConstructorsDeclared,
+ NumImplicitMoveConstructors);
fprintf(stderr, " %u/%u implicit copy assignment operators created\n",
NumImplicitCopyAssignmentOperatorsDeclared,
NumImplicitCopyAssignmentOperators);
+ if (getLangOptions().CPlusPlus)
+ fprintf(stderr, " %u/%u implicit move assignment operators created\n",
+ NumImplicitMoveAssignmentOperatorsDeclared,
+ NumImplicitMoveAssignmentOperators);
fprintf(stderr, " %u/%u implicit destructors created\n",
NumImplicitDestructorsDeclared, NumImplicitDestructors);
@@ -546,8 +559,28 @@ bool ASTContext::ZeroBitfieldFollowsNonBitfield(const FieldDecl *FD,
bool ASTContext::ZeroBitfieldFollowsBitfield(const FieldDecl *FD,
const FieldDecl *LastFD) const {
return (FD->isBitField() && LastFD && LastFD->isBitField() &&
- FD->getBitWidth()-> EvaluateAsInt(*this).getZExtValue() == 0);
+ FD->getBitWidth()-> EvaluateAsInt(*this).getZExtValue() == 0 &&
+ LastFD->getBitWidth()-> EvaluateAsInt(*this).getZExtValue() != 0);
+
+}
+bool ASTContext::BitfieldFollowsBitfield(const FieldDecl *FD,
+ const FieldDecl *LastFD) const {
+ return (FD->isBitField() && LastFD && LastFD->isBitField() &&
+ FD->getBitWidth()-> EvaluateAsInt(*this).getZExtValue() &&
+ LastFD->getBitWidth()-> EvaluateAsInt(*this).getZExtValue());
+}
+
+bool ASTContext::NoneBitfieldFollowsBitfield(const FieldDecl *FD,
+ const FieldDecl *LastFD) const {
+ return (!FD->isBitField() && LastFD && LastFD->isBitField() &&
+ LastFD->getBitWidth()-> EvaluateAsInt(*this).getZExtValue());
+}
+
+bool ASTContext::BitfieldFollowsNoneBitfield(const FieldDecl *FD,
+ const FieldDecl *LastFD) const {
+ return (FD->isBitField() && LastFD && !LastFD->isBitField() &&
+ FD->getBitWidth()-> EvaluateAsInt(*this).getZExtValue());
}
ASTContext::overridden_cxx_method_iterator
@@ -627,6 +660,10 @@ CharUnits ASTContext::getDeclAlign(const Decl *D, bool RefAsPointee) const {
UseAlignAttrOnly = true;
}
}
+ else if (isa<FieldDecl>(D))
+ UseAlignAttrOnly =
+ D->hasAttr<PackedAttr>() ||
+ cast<FieldDecl>(D)->getParent()->hasAttr<PackedAttr>();
// If we're using the align attribute only, just ignore everything
// else about the declaration and its type.
@@ -950,6 +987,9 @@ ASTContext::getTypeInfo(const Type *T) const {
return getTypeInfo(cast<DecltypeType>(T)->getUnderlyingExpr()->getType()
.getTypePtr());
+ case Type::UnaryTransform:
+ return getTypeInfo(cast<UnaryTransformType>(T)->getUnderlyingType());
+
case Type::Elaborated:
return getTypeInfo(cast<ElaboratedType>(T)->getNamedType().getTypePtr());
@@ -957,13 +997,18 @@ ASTContext::getTypeInfo(const Type *T) const {
return getTypeInfo(
cast<AttributedType>(T)->getEquivalentType().getTypePtr());
- case Type::TemplateSpecialization:
+ case Type::TemplateSpecialization: {
assert(getCanonicalType(T) != T &&
"Cannot request the size of a dependent type");
- // FIXME: this is likely to be wrong once we support template
- // aliases, since a template alias could refer to a typedef that
- // has an __aligned__ attribute on it.
- return getTypeInfo(getCanonicalType(T));
+ const TemplateSpecializationType *TST = cast<TemplateSpecializationType>(T);
+ // A type alias template specialization may refer to a typedef with the
+ // aligned attribute on it.
+ if (TST->isTypeAlias())
+ return getTypeInfo(TST->getAliasedType().getTypePtr());
+ else
+ return getTypeInfo(getCanonicalType(T));
+ }
+
}
assert(Align && (Align & (Align-1)) == 0 && "Alignment must be power of 2");
@@ -1393,6 +1438,9 @@ QualType ASTContext::getBlockPointerType(QualType T) const {
/// lvalue reference to the specified type.
QualType
ASTContext::getLValueReferenceType(QualType T, bool SpelledAsLValue) const {
+ assert(getCanonicalType(T) != OverloadTy &&
+ "Unresolved overloaded function type");
+
// Unique pointers, to guarantee there is only one pointer of a particular
// structure.
llvm::FoldingSetNodeID ID;
@@ -1572,6 +1620,7 @@ QualType ASTContext::getVariableArrayDecayedType(QualType type) const {
case Type::TypeOfExpr:
case Type::TypeOf:
case Type::Decltype:
+ case Type::UnaryTransform:
case Type::DependentName:
case Type::InjectedClassName:
case Type::TemplateSpecialization:
@@ -2235,10 +2284,10 @@ TypeSourceInfo *
ASTContext::getTemplateSpecializationTypeInfo(TemplateName Name,
SourceLocation NameLoc,
const TemplateArgumentListInfo &Args,
- QualType CanonType) const {
+ QualType Underlying) const {
assert(!Name.getAsDependentTemplateName() &&
"No dependent template names here!");
- QualType TST = getTemplateSpecializationType(Name, Args, CanonType);
+ QualType TST = getTemplateSpecializationType(Name, Args, Underlying);
TypeSourceInfo *DI = CreateTypeSourceInfo(TST);
TemplateSpecializationTypeLoc TL
@@ -2254,7 +2303,7 @@ ASTContext::getTemplateSpecializationTypeInfo(TemplateName Name,
QualType
ASTContext::getTemplateSpecializationType(TemplateName Template,
const TemplateArgumentListInfo &Args,
- QualType Canon) const {
+ QualType Underlying) const {
assert(!Template.getAsDependentTemplateName() &&
"No dependent template names here!");
@@ -2266,35 +2315,46 @@ ASTContext::getTemplateSpecializationType(TemplateName Template,
ArgVec.push_back(Args[i].getArgument());
return getTemplateSpecializationType(Template, ArgVec.data(), NumArgs,
- Canon);
+ Underlying);
}
QualType
ASTContext::getTemplateSpecializationType(TemplateName Template,
const TemplateArgument *Args,
unsigned NumArgs,
- QualType Canon) const {
+ QualType Underlying) const {
assert(!Template.getAsDependentTemplateName() &&
"No dependent template names here!");
// Look through qualified template names.
if (QualifiedTemplateName *QTN = Template.getAsQualifiedTemplateName())
Template = TemplateName(QTN->getTemplateDecl());
- if (!Canon.isNull())
- Canon = getCanonicalType(Canon);
- else
- Canon = getCanonicalTemplateSpecializationType(Template, Args, NumArgs);
+ bool isTypeAlias =
+ Template.getAsTemplateDecl() &&
+ isa<TypeAliasTemplateDecl>(Template.getAsTemplateDecl());
+
+ QualType CanonType;
+ if (!Underlying.isNull())
+ CanonType = getCanonicalType(Underlying);
+ else {
+ assert(!isTypeAlias &&
+ "Underlying type for template alias must be computed by caller");
+ CanonType = getCanonicalTemplateSpecializationType(Template, Args,
+ NumArgs);
+ }
// Allocate the (non-canonical) template specialization type, but don't
// try to unique it: these types typically have location information that
// we don't unique and don't want to lose.
- void *Mem = Allocate((sizeof(TemplateSpecializationType) +
- sizeof(TemplateArgument) * NumArgs),
+ void *Mem = Allocate(sizeof(TemplateSpecializationType) +
+ sizeof(TemplateArgument) * NumArgs +
+ (isTypeAlias ? sizeof(QualType) : 0),
TypeAlignment);
TemplateSpecializationType *Spec
= new (Mem) TemplateSpecializationType(Template,
Args, NumArgs,
- Canon);
+ CanonType,
+ isTypeAlias ? Underlying : QualType());
Types.push_back(Spec);
return QualType(Spec, 0);
@@ -2306,6 +2366,10 @@ ASTContext::getCanonicalTemplateSpecializationType(TemplateName Template,
unsigned NumArgs) const {
assert(!Template.getAsDependentTemplateName() &&
"No dependent template names here!");
+ assert((!Template.getAsTemplateDecl() ||
+ !isa<TypeAliasTemplateDecl>(Template.getAsTemplateDecl())) &&
+ "Underlying type for template alias must be computed by caller");
+
// Look through qualified template names.
if (QualifiedTemplateName *QTN = Template.getAsQualifiedTemplateName())
Template = TemplateName(QTN->getTemplateDecl());
@@ -2334,7 +2398,7 @@ ASTContext::getCanonicalTemplateSpecializationType(TemplateName Template,
TypeAlignment);
Spec = new (Mem) TemplateSpecializationType(CanonTemplate,
CanonArgs.data(), NumArgs,
- QualType());
+ QualType(), QualType());
Types.push_back(Spec);
TemplateSpecializationTypes.InsertNode(Spec, InsertPos);
}
@@ -2754,6 +2818,21 @@ QualType ASTContext::getDecltypeType(Expr *e) const {
return QualType(dt, 0);
}
+/// getUnaryTransformationType - We don't unique these, since the memory
+/// savings are minimal and these are rare.
+QualType ASTContext::getUnaryTransformType(QualType BaseType,
+ QualType UnderlyingType,
+ UnaryTransformType::UTTKind Kind)
+ const {
+ UnaryTransformType *Ty =
+ new (*this, TypeAlignment) UnaryTransformType (BaseType, UnderlyingType,
+ Kind,
+ UnderlyingType->isDependentType() ?
+ QualType() : UnderlyingType);
+ Types.push_back(Ty);
+ return QualType(Ty, 0);
+}
+
/// getAutoType - We only unique auto types after they've been deduced.
QualType ASTContext::getAutoType(QualType DeducedType) const {
void *InsertPos = 0;
@@ -3457,7 +3536,8 @@ QualType ASTContext::getCFConstantStringType() const {
SourceLocation(), 0,
FieldTypes[i], /*TInfo=*/0,
/*BitWidth=*/0,
- /*Mutable=*/false);
+ /*Mutable=*/false,
+ /*HasInit=*/false);
Field->setAccess(AS_public);
CFConstantStringTypeDecl->addDecl(Field);
}
@@ -3498,7 +3578,8 @@ QualType ASTContext::getNSConstantStringType() const {
SourceLocation(), 0,
FieldTypes[i], /*TInfo=*/0,
/*BitWidth=*/0,
- /*Mutable=*/false);
+ /*Mutable=*/false,
+ /*HasInit=*/false);
Field->setAccess(AS_public);
NSConstantStringTypeDecl->addDecl(Field);
}
@@ -3537,7 +3618,8 @@ QualType ASTContext::getObjCFastEnumerationStateType() const {
SourceLocation(), 0,
FieldTypes[i], /*TInfo=*/0,
/*BitWidth=*/0,
- /*Mutable=*/false);
+ /*Mutable=*/false,
+ /*HasInit=*/false);
Field->setAccess(AS_public);
ObjCFastEnumerationStateTypeDecl->addDecl(Field);
}
@@ -3574,7 +3656,8 @@ QualType ASTContext::getBlockDescriptorType() const {
&Idents.get(FieldNames[i]),
FieldTypes[i], /*TInfo=*/0,
/*BitWidth=*/0,
- /*Mutable=*/false);
+ /*Mutable=*/false,
+ /*HasInit=*/false);
Field->setAccess(AS_public);
T->addDecl(Field);
}
@@ -3622,7 +3705,8 @@ QualType ASTContext::getBlockDescriptorExtendedType() const {
&Idents.get(FieldNames[i]),
FieldTypes[i], /*TInfo=*/0,
/*BitWidth=*/0,
- /*Mutable=*/false);
+ /*Mutable=*/false,
+ /*HasInit=*/false);
Field->setAccess(AS_public);
T->addDecl(Field);
}
@@ -3650,7 +3734,7 @@ bool ASTContext::BlockRequiresCopying(QualType Ty) const {
if (getLangOptions().CPlusPlus) {
if (const RecordType *RT = Ty->getAs<RecordType>()) {
CXXRecordDecl *RD = cast<CXXRecordDecl>(RT->getDecl());
- return RD->hasConstCopyConstructor(*this);
+ return RD->hasConstCopyConstructor();
}
}
@@ -3707,7 +3791,8 @@ ASTContext::BuildByRefType(llvm::StringRef DeclName, QualType Ty) const {
SourceLocation(),
&Idents.get(FieldNames[i]),
FieldTypes[i], /*TInfo=*/0,
- /*BitWidth=*/0, /*Mutable=*/false);
+ /*BitWidth=*/0, /*Mutable=*/false,
+ /*HasInit=*/false);
Field->setAccess(AS_public);
T->addDecl(Field);
}
@@ -3736,6 +3821,9 @@ static bool isTypeTypedefedAsBOOL(QualType T) {
/// getObjCEncodingTypeSize returns size of type for objective-c encoding
/// purpose.
CharUnits ASTContext::getObjCEncodingTypeSize(QualType type) const {
+ if (!type->isIncompleteArrayType() && type->isIncompleteType())
+ return CharUnits::Zero();
+
CharUnits sz = getTypeSizeInChars(type);
// Make all integer and enum types at least as large as an int
@@ -3803,7 +3891,7 @@ std::string ASTContext::getObjCEncodingForBlock(const BlockExpr *Expr) const {
return S;
}
-void ASTContext::getObjCEncodingForFunctionDecl(const FunctionDecl *Decl,
+bool ASTContext::getObjCEncodingForFunctionDecl(const FunctionDecl *Decl,
std::string& S) {
// Encode result type.
getObjCEncodingForType(Decl->getResultType(), S);
@@ -3813,8 +3901,11 @@ void ASTContext::getObjCEncodingForFunctionDecl(const FunctionDecl *Decl,
E = Decl->param_end(); PI != E; ++PI) {
QualType PType = (*PI)->getType();
CharUnits sz = getObjCEncodingTypeSize(PType);
+ if (sz.isZero())
+ return true;
+
assert (sz.isPositive() &&
- "getObjCEncodingForMethodDecl - Incomplete param type");
+ "getObjCEncodingForFunctionDecl - Incomplete param type");
ParmOffset += sz;
}
S += charUnitsToString(ParmOffset);
@@ -3837,11 +3928,13 @@ void ASTContext::getObjCEncodingForFunctionDecl(const FunctionDecl *Decl,
S += charUnitsToString(ParmOffset);
ParmOffset += getObjCEncodingTypeSize(PType);
}
+
+ return false;
}
/// getObjCEncodingForMethodDecl - Return the encoded type for this method
/// declaration.
-void ASTContext::getObjCEncodingForMethodDecl(const ObjCMethodDecl *Decl,
+bool ASTContext::getObjCEncodingForMethodDecl(const ObjCMethodDecl *Decl,
std::string& S) const {
// FIXME: This is not very efficient.
// Encode type qualifer, 'in', 'inout', etc. for the return type.
@@ -3860,6 +3953,9 @@ void ASTContext::getObjCEncodingForMethodDecl(const ObjCMethodDecl *Decl,
E = Decl->sel_param_end(); PI != E; ++PI) {
QualType PType = (*PI)->getType();
CharUnits sz = getObjCEncodingTypeSize(PType);
+ if (sz.isZero())
+ return true;
+
assert (sz.isPositive() &&
"getObjCEncodingForMethodDecl - Incomplete param type");
ParmOffset += sz;
@@ -3889,6 +3985,8 @@ void ASTContext::getObjCEncodingForMethodDecl(const ObjCMethodDecl *Decl,
S += charUnitsToString(ParmOffset);
ParmOffset += getObjCEncodingTypeSize(PType);
}
+
+ return false;
}
/// getObjCEncodingForPropertyDecl - Return the encoded type for this
@@ -4108,7 +4206,8 @@ void ASTContext::getObjCEncodingForTypeImpl(QualType T, std::string& S,
bool ExpandStructures,
const FieldDecl *FD,
bool OutermostType,
- bool EncodingProperty) const {
+ bool EncodingProperty,
+ bool StructField) const {
if (T->getAs<BuiltinType>()) {
if (FD && FD->isBitField())
return EncodeBitField(this, S, T, FD);
@@ -4193,7 +4292,7 @@ void ASTContext::getObjCEncodingForTypeImpl(QualType T, std::string& S,
if (const ArrayType *AT =
// Ignore type qualifiers etc.
dyn_cast<ArrayType>(T->getCanonicalTypeInternal())) {
- if (isa<IncompleteArrayType>(AT)) {
+ if (isa<IncompleteArrayType>(AT) && !StructField) {
// Incomplete arrays are encoded as a pointer to the array element.
S += '^';
@@ -4202,11 +4301,15 @@ void ASTContext::getObjCEncodingForTypeImpl(QualType T, std::string& S,
} else {
S += '[';
- if (const ConstantArrayType *CAT = dyn_cast<ConstantArrayType>(AT))
- S += llvm::utostr(CAT->getSize().getZExtValue());
- else {
+ if (const ConstantArrayType *CAT = dyn_cast<ConstantArrayType>(AT)) {
+ if (getTypeSize(CAT->getElementType()) == 0)
+ S += '0';
+ else
+ S += llvm::utostr(CAT->getSize().getZExtValue());
+ } else {
//Variable length arrays are encoded as a regular array with 0 elements.
- assert(isa<VariableArrayType>(AT) && "Unknown array type!");
+ assert((isa<VariableArrayType>(AT) || isa<IncompleteArrayType>(AT)) &&
+ "Unknown array type!");
S += '0';
}
@@ -4244,24 +4347,30 @@ void ASTContext::getObjCEncodingForTypeImpl(QualType T, std::string& S,
}
if (ExpandStructures) {
S += '=';
- for (RecordDecl::field_iterator Field = RDecl->field_begin(),
- FieldEnd = RDecl->field_end();
- Field != FieldEnd; ++Field) {
- if (FD) {
- S += '"';
- S += Field->getNameAsString();
- S += '"';
- }
+ if (!RDecl->isUnion()) {
+ getObjCEncodingForStructureImpl(RDecl, S, FD);
+ } else {
+ for (RecordDecl::field_iterator Field = RDecl->field_begin(),
+ FieldEnd = RDecl->field_end();
+ Field != FieldEnd; ++Field) {
+ if (FD) {
+ S += '"';
+ S += Field->getNameAsString();
+ S += '"';
+ }
- // Special case bit-fields.
- if (Field->isBitField()) {
- getObjCEncodingForTypeImpl(Field->getType(), S, false, true,
- (*Field));
- } else {
- QualType qt = Field->getType();
- getLegacyIntegralTypeEncoding(qt);
- getObjCEncodingForTypeImpl(qt, S, false, true,
- FD);
+ // Special case bit-fields.
+ if (Field->isBitField()) {
+ getObjCEncodingForTypeImpl(Field->getType(), S, false, true,
+ (*Field));
+ } else {
+ QualType qt = Field->getType();
+ getLegacyIntegralTypeEncoding(qt);
+ getObjCEncodingForTypeImpl(qt, S, false, true,
+ FD, /*OutermostType*/false,
+ /*EncodingProperty*/false,
+ /*StructField*/true);
+ }
}
}
}
@@ -4382,6 +4491,135 @@ void ASTContext::getObjCEncodingForTypeImpl(QualType T, std::string& S,
assert(0 && "@encode for type not implemented!");
}
+void ASTContext::getObjCEncodingForStructureImpl(RecordDecl *RDecl,
+ std::string &S,
+ const FieldDecl *FD,
+ bool includeVBases) const {
+ assert(RDecl && "Expected non-null RecordDecl");
+ assert(!RDecl->isUnion() && "Should not be called for unions");
+ if (!RDecl->getDefinition())
+ return;
+
+ CXXRecordDecl *CXXRec = dyn_cast<CXXRecordDecl>(RDecl);
+ std::multimap<uint64_t, NamedDecl *> FieldOrBaseOffsets;
+ const ASTRecordLayout &layout = getASTRecordLayout(RDecl);
+
+ if (CXXRec) {
+ for (CXXRecordDecl::base_class_iterator
+ BI = CXXRec->bases_begin(),
+ BE = CXXRec->bases_end(); BI != BE; ++BI) {
+ if (!BI->isVirtual()) {
+ CXXRecordDecl *base = BI->getType()->getAsCXXRecordDecl();
+ uint64_t offs = layout.getBaseClassOffsetInBits(base);
+ FieldOrBaseOffsets.insert(FieldOrBaseOffsets.upper_bound(offs),
+ std::make_pair(offs, base));
+ }
+ }
+ }
+
+ unsigned i = 0;
+ for (RecordDecl::field_iterator Field = RDecl->field_begin(),
+ FieldEnd = RDecl->field_end();
+ Field != FieldEnd; ++Field, ++i) {
+ uint64_t offs = layout.getFieldOffset(i);
+ FieldOrBaseOffsets.insert(FieldOrBaseOffsets.upper_bound(offs),
+ std::make_pair(offs, *Field));
+ }
+
+ if (CXXRec && includeVBases) {
+ for (CXXRecordDecl::base_class_iterator
+ BI = CXXRec->vbases_begin(),
+ BE = CXXRec->vbases_end(); BI != BE; ++BI) {
+ CXXRecordDecl *base = BI->getType()->getAsCXXRecordDecl();
+ uint64_t offs = layout.getVBaseClassOffsetInBits(base);
+ FieldOrBaseOffsets.insert(FieldOrBaseOffsets.upper_bound(offs),
+ std::make_pair(offs, base));
+ }
+ }
+
+ CharUnits size;
+ if (CXXRec) {
+ size = includeVBases ? layout.getSize() : layout.getNonVirtualSize();
+ } else {
+ size = layout.getSize();
+ }
+
+ uint64_t CurOffs = 0;
+ std::multimap<uint64_t, NamedDecl *>::iterator
+ CurLayObj = FieldOrBaseOffsets.begin();
+
+ if (CurLayObj != FieldOrBaseOffsets.end() && CurLayObj->first != 0) {
+ assert(CXXRec && CXXRec->isDynamicClass() &&
+ "Offset 0 was empty but no VTable ?");
+ if (FD) {
+ S += "\"_vptr$";
+ std::string recname = CXXRec->getNameAsString();
+ if (recname.empty()) recname = "?";
+ S += recname;
+ S += '"';
+ }
+ S += "^^?";
+ CurOffs += getTypeSize(VoidPtrTy);
+ }
+
+ if (!RDecl->hasFlexibleArrayMember()) {
+ // Mark the end of the structure.
+ uint64_t offs = toBits(size);
+ FieldOrBaseOffsets.insert(FieldOrBaseOffsets.upper_bound(offs),
+ std::make_pair(offs, (NamedDecl*)0));
+ }
+
+ for (; CurLayObj != FieldOrBaseOffsets.end(); ++CurLayObj) {
+ assert(CurOffs <= CurLayObj->first);
+
+ if (CurOffs < CurLayObj->first) {
+ uint64_t padding = CurLayObj->first - CurOffs;
+ // FIXME: There doesn't seem to be a way to indicate in the encoding that
+ // packing/alignment of members is different that normal, in which case
+ // the encoding will be out-of-sync with the real layout.
+ // If the runtime switches to just consider the size of types without
+ // taking into account alignment, we could make padding explicit in the
+ // encoding (e.g. using arrays of chars). The encoding strings would be
+ // longer then though.
+ CurOffs += padding;
+ }
+
+ NamedDecl *dcl = CurLayObj->second;
+ if (dcl == 0)
+ break; // reached end of structure.
+
+ if (CXXRecordDecl *base = dyn_cast<CXXRecordDecl>(dcl)) {
+ // We expand the bases without their virtual bases since those are going
+ // in the initial structure. Note that this differs from gcc which
+ // expands virtual bases each time one is encountered in the hierarchy,
+ // making the encoding type bigger than it really is.
+ getObjCEncodingForStructureImpl(base, S, FD, /*includeVBases*/false);
+ if (!base->isEmpty())
+ CurOffs += toBits(getASTRecordLayout(base).getNonVirtualSize());
+ } else {
+ FieldDecl *field = cast<FieldDecl>(dcl);
+ if (FD) {
+ S += '"';
+ S += field->getNameAsString();
+ S += '"';
+ }
+
+ if (field->isBitField()) {
+ EncodeBitField(this, S, field->getType(), field);
+ CurOffs += field->getBitWidth()->EvaluateAsInt(*this).getZExtValue();
+ } else {
+ QualType qt = field->getType();
+ getLegacyIntegralTypeEncoding(qt);
+ getObjCEncodingForTypeImpl(qt, S, false, true, FD,
+ /*OutermostType*/false,
+ /*EncodingProperty*/false,
+ /*StructField*/true);
+ CurOffs += getTypeSize(field->getType());
+ }
+ }
+ }
+}
+
void ASTContext::getObjCEncodingForTypeQualifier(Decl::ObjCDeclQualifier QT,
std::string& S) const {
if (QT & Decl::OBJC_TQ_In)
@@ -6068,7 +6306,7 @@ bool ASTContext::DeclMustBeEmitted(const Decl *D) {
if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
// Forward declarations aren't required.
- if (!FD->isThisDeclarationADefinition())
+ if (!FD->doesThisDeclarationHaveABody())
return false;
// Constructors and destructors are required.
@@ -6105,10 +6343,13 @@ bool ASTContext::DeclMustBeEmitted(const Decl *D) {
// Structs that have non-trivial constructors or destructors are required.
// FIXME: Handle references.
+ // FIXME: Be more selective about which constructors we care about.
if (const RecordType *RT = VD->getType()->getAs<RecordType>()) {
if (const CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(RT->getDecl())) {
- if (RD->hasDefinition() &&
- (!RD->hasTrivialConstructor() || !RD->hasTrivialDestructor()))
+ if (RD->hasDefinition() && !(RD->hasTrivialDefaultConstructor() &&
+ RD->hasTrivialCopyConstructor() &&
+ RD->hasTrivialMoveConstructor() &&
+ RD->hasTrivialDestructor()))
return true;
}
}
diff --git a/lib/AST/ASTDiagnostic.cpp b/lib/AST/ASTDiagnostic.cpp
index 897b4a4..16d2f85 100644
--- a/lib/AST/ASTDiagnostic.cpp
+++ b/lib/AST/ASTDiagnostic.cpp
@@ -56,9 +56,11 @@ static QualType Desugar(ASTContext &Context, QualType QT, bool &ShouldAKA) {
continue;
}
- // Don't desugar template specializations.
- if (isa<TemplateSpecializationType>(Ty))
- break;
+ // Don't desugar template specializations, unless it's an alias template.
+ if (const TemplateSpecializationType *TST
+ = dyn_cast<TemplateSpecializationType>(Ty))
+ if (!TST->isTypeAlias())
+ break;
// Don't desugar magic Objective-C types.
if (QualType(Ty,0) == Context.getObjCIdType() ||
diff --git a/lib/AST/ASTImporter.cpp b/lib/AST/ASTImporter.cpp
index dc881ba..100e604 100644
--- a/lib/AST/ASTImporter.cpp
+++ b/lib/AST/ASTImporter.cpp
@@ -64,6 +64,7 @@ namespace {
// FIXME: DependentTypeOfExprType
QualType VisitTypeOfType(const TypeOfType *T);
QualType VisitDecltypeType(const DecltypeType *T);
+ QualType VisitUnaryTransformType(const UnaryTransformType *T);
QualType VisitAutoType(const AutoType *T);
// FIXME: DependentDecltypeType
QualType VisitRecordType(const RecordType *T);
@@ -604,7 +605,14 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
cast<TypeOfType>(T2)->getUnderlyingType()))
return false;
break;
-
+
+ case Type::UnaryTransform:
+ if (!IsStructurallyEquivalent(Context,
+ cast<UnaryTransformType>(T1)->getUnderlyingType(),
+ cast<UnaryTransformType>(T1)->getUnderlyingType()))
+ return false;
+ break;
+
case Type::Decltype:
if (!IsStructurallyEquivalent(Context,
cast<DecltypeType>(T1)->getUnderlyingExpr(),
@@ -1572,6 +1580,17 @@ QualType ASTNodeImporter::VisitDecltypeType(const DecltypeType *T) {
return Importer.getToContext().getDecltypeType(ToExpr);
}
+QualType ASTNodeImporter::VisitUnaryTransformType(const UnaryTransformType *T) {
+ QualType ToBaseType = Importer.Import(T->getBaseType());
+ QualType ToUnderlyingType = Importer.Import(T->getUnderlyingType());
+ if (ToBaseType.isNull() || ToUnderlyingType.isNull())
+ return QualType();
+
+ return Importer.getToContext().getUnaryTransformType(ToBaseType,
+ ToUnderlyingType,
+ T->getUTTKind());
+}
+
QualType ASTNodeImporter::VisitAutoType(const AutoType *T) {
// FIXME: Make sure that the "to" context supports C++0x!
QualType FromDeduced = T->getDeducedType();
@@ -2493,9 +2512,12 @@ Decl *ASTNodeImporter::VisitFieldDecl(FieldDecl *D) {
FieldDecl *ToField = FieldDecl::Create(Importer.getToContext(), DC,
Importer.Import(D->getInnerLocStart()),
Loc, Name.getAsIdentifierInfo(),
- T, TInfo, BitWidth, D->isMutable());
+ T, TInfo, BitWidth, D->isMutable(),
+ D->hasInClassInitializer());
ToField->setAccess(D->getAccess());
ToField->setLexicalDeclContext(LexicalDC);
+ if (ToField->hasInClassInitializer())
+ ToField->setInClassInitializer(D->getInClassInitializer());
Importer.Imported(D, ToField);
LexicalDC->addDecl(ToField);
return ToField;
@@ -2851,7 +2873,8 @@ Decl *ASTNodeImporter::VisitObjCMethodDecl(ObjCMethodDecl *D) {
D->isVariadic(),
D->isSynthesized(),
D->isDefined(),
- D->getImplementationControl());
+ D->getImplementationControl(),
+ D->hasRelatedResultType());
// FIXME: When we decide to merge method definitions, we'll need to
// deal with implicit parameters.
diff --git a/lib/AST/Decl.cpp b/lib/AST/Decl.cpp
index b21ba9a..12357c0 100644
--- a/lib/AST/Decl.cpp
+++ b/lib/AST/Decl.cpp
@@ -1422,6 +1422,31 @@ bool FunctionDecl::hasBody(const FunctionDecl *&Definition) const {
return false;
}
+bool FunctionDecl::hasTrivialBody() const
+{
+ Stmt *S = getBody();
+ if (!S) {
+ // Since we don't have a body for this function, we don't know if it's
+ // trivial or not.
+ return false;
+ }
+
+ if (isa<CompoundStmt>(S) && cast<CompoundStmt>(S)->body_empty())
+ return true;
+ return false;
+}
+
+bool FunctionDecl::isDefined(const FunctionDecl *&Definition) const {
+ for (redecl_iterator I = redecls_begin(), E = redecls_end(); I != E; ++I) {
+ if (I->IsDeleted || I->IsDefaulted || I->Body || I->IsLateTemplateParsed) {
+ Definition = I->IsDeleted ? I->getCanonicalDecl() : *I;
+ return true;
+ }
+ }
+
+ return false;
+}
+
Stmt *FunctionDecl::getBody(const FunctionDecl *&Definition) const {
for (redecl_iterator I = redecls_begin(), E = redecls_end(); I != E; ++I) {
if (I->Body) {
@@ -1450,10 +1475,34 @@ void FunctionDecl::setPure(bool P) {
}
bool FunctionDecl::isMain() const {
- ASTContext &Context = getASTContext();
- return !Context.getLangOptions().Freestanding &&
- getDeclContext()->getRedeclContext()->isTranslationUnit() &&
- getIdentifier() && getIdentifier()->isStr("main");
+ const TranslationUnitDecl *tunit =
+ dyn_cast<TranslationUnitDecl>(getDeclContext()->getRedeclContext());
+ return tunit &&
+ !tunit->getASTContext().getLangOptions().Freestanding &&
+ getIdentifier() &&
+ getIdentifier()->isStr("main");
+}
+
+bool FunctionDecl::isReservedGlobalPlacementOperator() const {
+ assert(getDeclName().getNameKind() == DeclarationName::CXXOperatorName);
+ assert(getDeclName().getCXXOverloadedOperator() == OO_New ||
+ getDeclName().getCXXOverloadedOperator() == OO_Delete ||
+ getDeclName().getCXXOverloadedOperator() == OO_Array_New ||
+ getDeclName().getCXXOverloadedOperator() == OO_Array_Delete);
+
+ if (isa<CXXRecordDecl>(getDeclContext())) return false;
+ assert(getDeclContext()->getRedeclContext()->isTranslationUnit());
+
+ const FunctionProtoType *proto = getType()->castAs<FunctionProtoType>();
+ if (proto->getNumArgs() != 2 || proto->isVariadic()) return false;
+
+ ASTContext &Context =
+ cast<TranslationUnitDecl>(getDeclContext()->getRedeclContext())
+ ->getASTContext();
+
+ // The result type and first argument type are constant across all
+ // these operators. The second argument must be exactly void*.
+ return (proto->getArgType(1).getCanonicalType() == Context.VoidPtrTy);
}
bool FunctionDecl::isExternC() const {
@@ -1690,11 +1739,11 @@ bool FunctionDecl::isInlined() const {
/// an externally visible symbol, but "extern inline" will not create an
/// externally visible symbol.
bool FunctionDecl::isInlineDefinitionExternallyVisible() const {
- assert(isThisDeclarationADefinition() && "Must have the function definition");
+ assert(doesThisDeclarationHaveABody() && "Must have the function definition");
assert(isInlined() && "Function must be inline");
ASTContext &Context = getASTContext();
- if (!Context.getLangOptions().C99 || hasAttr<GNUInlineAttr>()) {
+ if (Context.getLangOptions().GNUInline || hasAttr<GNUInlineAttr>()) {
// If it's not the case that both 'inline' and 'extern' are
// specified on the definition, then this inline definition is
// externally visible.
@@ -2028,9 +2077,10 @@ SourceRange FunctionDecl::getSourceRange() const {
FieldDecl *FieldDecl::Create(const ASTContext &C, DeclContext *DC,
SourceLocation StartLoc, SourceLocation IdLoc,
IdentifierInfo *Id, QualType T,
- TypeSourceInfo *TInfo, Expr *BW, bool Mutable) {
+ TypeSourceInfo *TInfo, Expr *BW, bool Mutable,
+ bool HasInit) {
return new (C) FieldDecl(Decl::Field, DC, StartLoc, IdLoc, Id, T, TInfo,
- BW, Mutable);
+ BW, Mutable, HasInit);
}
bool FieldDecl::isAnonymousStructOrUnion() const {
@@ -2059,8 +2109,7 @@ unsigned FieldDecl::getFieldIndex() const {
if (IsMsStruct) {
// Zero-length bitfields following non-bitfield members are ignored.
- if (getASTContext().ZeroBitfieldFollowsNonBitfield((*i), LastFD) ||
- getASTContext().ZeroBitfieldFollowsBitfield((*i), LastFD)) {
+ if (getASTContext().ZeroBitfieldFollowsNonBitfield((*i), LastFD)) {
++i;
continue;
}
@@ -2076,10 +2125,17 @@ unsigned FieldDecl::getFieldIndex() const {
SourceRange FieldDecl::getSourceRange() const {
if (isBitField())
- return SourceRange(getInnerLocStart(), BitWidth->getLocEnd());
+ return SourceRange(getInnerLocStart(), getBitWidth()->getLocEnd());
return DeclaratorDecl::getSourceRange();
}
+void FieldDecl::setInClassInitializer(Expr *Init) {
+ assert(!InitializerOrBitWidth.getPointer() &&
+ "bit width or initializer already set");
+ InitializerOrBitWidth.setPointer(Init);
+ InitializerOrBitWidth.setInt(0);
+}
+
//===----------------------------------------------------------------------===//
// TagDecl Implementation
//===----------------------------------------------------------------------===//
diff --git a/lib/AST/DeclBase.cpp b/lib/AST/DeclBase.cpp
index 6d517c5..1766d39 100644
--- a/lib/AST/DeclBase.cpp
+++ b/lib/AST/DeclBase.cpp
@@ -439,6 +439,7 @@ unsigned Decl::getIdentifierNamespaceForKind(Kind DeclKind) {
case Typedef:
case TypeAlias:
+ case TypeAliasTemplate:
case UnresolvedUsingTypename:
case TemplateTypeParm:
return IDNS_Ordinary | IDNS_Type;
@@ -1165,10 +1166,10 @@ void DeclContext::makeDeclVisibleInContextImpl(NamedDecl *D) {
if (!D->getDeclName())
return;
- // FIXME: This feels like a hack. Should DeclarationName support
- // template-ids, or is there a better way to keep specializations
- // from being visible?
- if (isa<ClassTemplateSpecializationDecl>(D) || D->isTemplateParameter())
+ // Skip entities that can't be found by name lookup into a particular
+ // context.
+ if ((D->getIdentifierNamespace() == 0 && !isa<UsingDirectiveDecl>(D)) ||
+ D->isTemplateParameter())
return;
ASTContext *C = 0;
diff --git a/lib/AST/DeclCXX.cpp b/lib/AST/DeclCXX.cpp
index 9099cd5..08ac2a5 100644
--- a/lib/AST/DeclCXX.cpp
+++ b/lib/AST/DeclCXX.cpp
@@ -29,19 +29,21 @@ using namespace clang;
CXXRecordDecl::DefinitionData::DefinitionData(CXXRecordDecl *D)
: UserDeclaredConstructor(false), UserDeclaredCopyConstructor(false),
- UserDeclaredCopyAssignment(false), UserDeclaredDestructor(false),
+ UserDeclaredMoveConstructor(false), UserDeclaredCopyAssignment(false),
+ UserDeclaredMoveAssignment(false), UserDeclaredDestructor(false),
Aggregate(true), PlainOldData(true), Empty(true), Polymorphic(false),
Abstract(false), IsStandardLayout(true), HasNoNonEmptyBases(true),
HasPrivateFields(false), HasProtectedFields(false), HasPublicFields(false),
- HasTrivialConstructor(true), HasConstExprNonCopyMoveConstructor(false),
- HasTrivialCopyConstructor(true), HasTrivialMoveConstructor(true),
- HasTrivialCopyAssignment(true), HasTrivialMoveAssignment(true),
- HasTrivialDestructor(true), HasNonLiteralTypeFieldsOrBases(false),
- ComputedVisibleConversions(false),
- DeclaredDefaultConstructor(false), DeclaredCopyConstructor(false),
- DeclaredCopyAssignment(false), DeclaredDestructor(false),
- NumBases(0), NumVBases(0), Bases(), VBases(),
- Definition(D), FirstFriend(0) {
+ HasMutableFields(false), HasTrivialDefaultConstructor(true),
+ HasConstExprNonCopyMoveConstructor(false), HasTrivialCopyConstructor(true),
+ HasTrivialMoveConstructor(true), HasTrivialCopyAssignment(true),
+ HasTrivialMoveAssignment(true), HasTrivialDestructor(true),
+ HasNonLiteralTypeFieldsOrBases(false), ComputedVisibleConversions(false),
+ UserProvidedDefaultConstructor(false), DeclaredDefaultConstructor(false),
+ DeclaredCopyConstructor(false), DeclaredMoveConstructor(false),
+ DeclaredCopyAssignment(false), DeclaredMoveAssignment(false),
+ DeclaredDestructor(false), NumBases(0), NumVBases(0), Bases(), VBases(),
+ Definition(D), FirstFriend(0) {
}
CXXRecordDecl::CXXRecordDecl(Kind K, TagKind TK, DeclContext *DC,
@@ -165,8 +167,9 @@ CXXRecordDecl::setBases(CXXBaseSpecifier const * const *Bases,
data().Empty = false;
// C++ [class.ctor]p5:
- // A constructor is trivial if its class has no virtual base classes.
- data().HasTrivialConstructor = false;
+ // A default constructor is trivial [...] if:
+ // -- its class has [...] no virtual bases
+ data().HasTrivialDefaultConstructor = false;
// C++0x [class.copy]p13:
// A copy/move constructor for class X is trivial if it is neither
@@ -188,10 +191,11 @@ CXXRecordDecl::setBases(CXXBaseSpecifier const * const *Bases,
data().IsStandardLayout = false;
} else {
// C++ [class.ctor]p5:
- // A constructor is trivial if all the direct base classes of its
- // class have trivial constructors.
- if (!BaseClassDecl->hasTrivialConstructor())
- data().HasTrivialConstructor = false;
+ // A default constructor is trivial [...] if:
+ // -- all the direct base classes of its class have trivial default
+ // constructors.
+ if (!BaseClassDecl->hasTrivialDefaultConstructor())
+ data().HasTrivialDefaultConstructor = false;
// C++0x [class.copy]p13:
// A copy/move constructor for class X is trivial if [...]
@@ -223,6 +227,10 @@ CXXRecordDecl::setBases(CXXBaseSpecifier const * const *Bases,
// have trivial destructors.
if (!BaseClassDecl->hasTrivialDestructor())
data().HasTrivialDestructor = false;
+
+ // Keep track of the presence of mutable fields.
+ if (BaseClassDecl->hasMutableFields())
+ data().HasMutableFields = true;
}
if (VBases.empty())
@@ -262,8 +270,8 @@ bool CXXRecordDecl::hasAnyDependentBases() const {
return !forallBases(SawBase, 0);
}
-bool CXXRecordDecl::hasConstCopyConstructor(const ASTContext &Context) const {
- return getCopyConstructor(Context, Qualifiers::Const) != 0;
+bool CXXRecordDecl::hasConstCopyConstructor() const {
+ return getCopyConstructor(Qualifiers::Const) != 0;
}
bool CXXRecordDecl::isTriviallyCopyable() const {
@@ -306,8 +314,8 @@ GetBestOverloadCandidateSimple(
return Cands[Best].first;
}
-CXXConstructorDecl *CXXRecordDecl::getCopyConstructor(const ASTContext &Context,
- unsigned TypeQuals) const{
+CXXConstructorDecl *CXXRecordDecl::getCopyConstructor(unsigned TypeQuals) const{
+ ASTContext &Context = getASTContext();
QualType ClassType
= Context.getTypeDeclType(const_cast<CXXRecordDecl*>(this));
DeclarationName ConstructorName
@@ -337,6 +345,14 @@ CXXConstructorDecl *CXXRecordDecl::getCopyConstructor(const ASTContext &Context,
GetBestOverloadCandidateSimple(Found));
}
+CXXConstructorDecl *CXXRecordDecl::getMoveConstructor() const {
+ for (ctor_iterator I = ctor_begin(), E = ctor_end(); I != E; ++I)
+ if (I->isMoveConstructor())
+ return *I;
+
+ return 0;
+}
+
CXXMethodDecl *CXXRecordDecl::getCopyAssignmentOperator(bool ArgIsConst) const {
ASTContext &Context = getASTContext();
QualType Class = Context.getTypeDeclType(const_cast<CXXRecordDecl *>(this));
@@ -387,6 +403,14 @@ CXXMethodDecl *CXXRecordDecl::getCopyAssignmentOperator(bool ArgIsConst) const {
return GetBestOverloadCandidateSimple(Found);
}
+CXXMethodDecl *CXXRecordDecl::getMoveAssignmentOperator() const {
+ for (method_iterator I = method_begin(), E = method_end(); I != E; ++I)
+ if (I->isMoveAssignmentOperator())
+ return *I;
+
+ return 0;
+}
+
void CXXRecordDecl::markedVirtualFunctionPure() {
// C++ [class.abstract]p2:
// A class is abstract if it has at least one pure virtual function.
@@ -421,8 +445,10 @@ void CXXRecordDecl::addedMember(Decl *D) {
// polymorphic class.
data().Polymorphic = true;
- // None of the special member functions are trivial.
- data().HasTrivialConstructor = false;
+ // C++0x [class.ctor]p5
+ // A default constructor is trivial [...] if:
+ // -- its class has no virtual functions [...]
+ data().HasTrivialDefaultConstructor = false;
// C++0x [class.copy]p13:
// A copy/move constructor for class X is trivial if [...]
@@ -451,32 +477,32 @@ void CXXRecordDecl::addedMember(Decl *D) {
if (ASTMutationListener *L = getASTMutationListener())
L->AddedCXXImplicitMember(data().Definition, D);
+ // If this is a special member function, note that it was added and then
+ // return early.
if (CXXConstructorDecl *Constructor = dyn_cast<CXXConstructorDecl>(D)) {
- // If this is the implicit default constructor, note that we have now
- // declared it.
if (Constructor->isDefaultConstructor())
data().DeclaredDefaultConstructor = true;
- // If this is the implicit copy constructor, note that we have now
- // declared it.
else if (Constructor->isCopyConstructor())
data().DeclaredCopyConstructor = true;
+ else if (Constructor->isMoveConstructor())
+ data().DeclaredMoveConstructor = true;
+ else
+ goto NotASpecialMember;
return;
- }
-
- if (isa<CXXDestructorDecl>(D)) {
+ } else if (isa<CXXDestructorDecl>(D)) {
data().DeclaredDestructor = true;
return;
- }
-
- if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(D)) {
- // If this is the implicit copy constructor, note that we have now
- // declared it.
- // FIXME: Move constructors
- if (Method->getOverloadedOperator() == OO_Equal)
+ } else if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(D)) {
+ if (Method->isCopyAssignmentOperator())
data().DeclaredCopyAssignment = true;
+ else if (Method->isMoveAssignmentOperator())
+ data().DeclaredMoveAssignment = true;
+ else
+ goto NotASpecialMember;
return;
}
+NotASpecialMember:;
// Any other implicit declarations are handled like normal declarations.
}
@@ -485,23 +511,20 @@ void CXXRecordDecl::addedMember(Decl *D) {
// Note that we have a user-declared constructor.
data().UserDeclaredConstructor = true;
- // Note that we have no need of an implicitly-declared default constructor.
- data().DeclaredDefaultConstructor = true;
-
- // C++ [dcl.init.aggr]p1:
- // An aggregate is an array or a class (clause 9) with no
- // user-declared constructors (12.1) [...].
- data().Aggregate = false;
-
- // C++ [class]p4:
- // A POD-struct is an aggregate class [...]
- data().PlainOldData = false;
-
- // C++ [class.ctor]p5:
- // A constructor is trivial if it is an implicitly-declared default
- // constructor.
- // FIXME: C++0x: don't do this for "= default" default constructors.
- data().HasTrivialConstructor = false;
+ // FIXME: Under C++0x, /only/ special member functions may be user-provided.
+ // This is probably a defect.
+ bool UserProvided = false;
+
+ // C++0x [class.ctor]p5:
+ // A default constructor is trivial if it is not user-provided [...]
+ if (Constructor->isDefaultConstructor()) {
+ data().DeclaredDefaultConstructor = true;
+ if (Constructor->isUserProvided()) {
+ data().HasTrivialDefaultConstructor = false;
+ data().UserProvidedDefaultConstructor = true;
+ UserProvided = true;
+ }
+ }
// Note when we have a user-declared copy or move constructor, which will
// suppress the implicit declaration of those constructors.
@@ -511,16 +534,23 @@ void CXXRecordDecl::addedMember(Decl *D) {
data().DeclaredCopyConstructor = true;
// C++0x [class.copy]p13:
- // A copy/move constructor for class X is trivial if it is neither
- // user-provided nor deleted
- // FIXME: C++0x: don't do this for "= default" copy constructors.
- data().HasTrivialCopyConstructor = false;
+ // A copy/move constructor for class X is trivial if it is not
+ // user-provided [...]
+ if (Constructor->isUserProvided()) {
+ data().HasTrivialCopyConstructor = false;
+ UserProvided = true;
+ }
} else if (Constructor->isMoveConstructor()) {
+ data().UserDeclaredMoveConstructor = true;
+ data().DeclaredMoveConstructor = true;
+
// C++0x [class.copy]p13:
- // A copy/move constructor for class X is trivial if it is neither
- // user-provided nor deleted
- // FIXME: C++0x: don't do this for "= default" move constructors.
- data().HasTrivialMoveConstructor = false;
+ // A copy/move constructor for class X is trivial if it is not
+ // user-provided [...]
+ if (Constructor->isUserProvided()) {
+ data().HasTrivialMoveConstructor = false;
+ UserProvided = true;
+ }
}
}
if (Constructor->isConstExpr() &&
@@ -530,88 +560,81 @@ void CXXRecordDecl::addedMember(Decl *D) {
data().HasConstExprNonCopyMoveConstructor = true;
}
+ // C++ [dcl.init.aggr]p1:
+ // An aggregate is an array or a class with no user-declared
+ // constructors [...].
+ // C++0x [dcl.init.aggr]p1:
+ // An aggregate is an array or a class with no user-provided
+ // constructors [...].
+ if (!getASTContext().getLangOptions().CPlusPlus0x || UserProvided)
+ data().Aggregate = false;
+
+ // C++ [class]p4:
+ // A POD-struct is an aggregate class [...]
+ // Since the POD bit is meant to be C++03 POD-ness, clear it even if the
+ // type is technically an aggregate in C++0x since it wouldn't be in 03.
+ data().PlainOldData = false;
+
return;
}
// Handle (user-declared) destructors.
- if (isa<CXXDestructorDecl>(D)) {
+ if (CXXDestructorDecl *DD = dyn_cast<CXXDestructorDecl>(D)) {
data().DeclaredDestructor = true;
data().UserDeclaredDestructor = true;
// C++ [class]p4:
// A POD-struct is an aggregate class that has [...] no user-defined
// destructor.
+ // This bit is the C++03 POD bit, not the 0x one.
data().PlainOldData = false;
- // C++ [class.dtor]p3:
- // A destructor is trivial if it is an implicitly-declared destructor and
- // [...].
- //
- // FIXME: C++0x: don't do this for "= default" destructors
- data().HasTrivialDestructor = false;
+ // C++0x [class.dtor]p5:
+ // A destructor is trivial if it is not user-provided and [...]
+ if (DD->isUserProvided())
+ data().HasTrivialDestructor = false;
return;
}
// Handle (user-declared) member functions.
if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(D)) {
- if (Method->getOverloadedOperator() == OO_Equal) {
- // We're interested specifically in copy assignment operators.
- const FunctionProtoType *FnType
- = Method->getType()->getAs<FunctionProtoType>();
- assert(FnType && "Overloaded operator has no proto function type.");
- assert(FnType->getNumArgs() == 1 && !FnType->isVariadic());
-
- // Copy assignment operators must be non-templates.
- if (Method->getPrimaryTemplate() || FunTmpl)
- return;
-
- ASTContext &Context = getASTContext();
- QualType ClassType = Context.getCanonicalType(Context.getTypeDeclType(
- const_cast<CXXRecordDecl*>(this)));
-
- bool isRValueRefArg = false;
- QualType ArgType = FnType->getArgType(0);
- if (const LValueReferenceType *Ref =
- ArgType->getAs<LValueReferenceType>()) {
- ArgType = Ref->getPointeeType();
- } else if (const RValueReferenceType *Ref =
- ArgType->getAs<RValueReferenceType>()) {
- ArgType = Ref->getPointeeType();
- isRValueRefArg = true;
- }
- if (!Context.hasSameUnqualifiedType(ClassType, ArgType))
- return;
-
+ if (Method->isCopyAssignmentOperator()) {
// C++ [class]p4:
// A POD-struct is an aggregate class that [...] has no user-defined
// copy assignment operator [...].
- // FIXME: This should be probably determined dynamically in terms of
- // other more precise attributes to correctly model how it is specified
- // in C++0x. Setting it here happens to do the right thing.
+ // This is the C++03 bit only.
data().PlainOldData = false;
- if (!isRValueRefArg) {
- // This is a copy assignment operator.
+ // This is a copy assignment operator.
- // Suppress the implicit declaration of a copy constructor.
- data().UserDeclaredCopyAssignment = true;
- data().DeclaredCopyAssignment = true;
+ // Suppress the implicit declaration of a copy constructor.
+ data().UserDeclaredCopyAssignment = true;
+ data().DeclaredCopyAssignment = true;
- // C++0x [class.copy]p27:
- // A copy/move assignment operator for class X is trivial if it is
- // neither user-provided nor deleted [...]
- // FIXME: C++0x: don't do this for "= default" copy operators.
+ // C++0x [class.copy]p27:
+ // A copy/move assignment operator for class X is trivial if it is
+ // neither user-provided nor deleted [...]
+ if (Method->isUserProvided())
data().HasTrivialCopyAssignment = false;
- } else {
- // This is a move assignment operator.
- // C++0x [class.copy]p27:
- // A copy/move assignment operator for class X is trivial if it is
- // neither user-provided nor deleted [...]
- // FIXME: C++0x: don't do this for "= default" copy operators.
+ return;
+ }
+
+ if (Method->isMoveAssignmentOperator()) {
+ // This is an extension in C++03 mode, but we'll keep consistency by
+ // taking a move assignment operator to induce non-POD-ness
+ data().PlainOldData = false;
+
+ // This is a move assignment operator.
+ data().UserDeclaredMoveAssignment = true;
+ data().DeclaredMoveAssignment = true;
+
+ // C++0x [class.copy]p27:
+ // A copy/move assignment operator for class X is trivial if it is
+ // neither user-provided nor deleted [...]
+ if (Method->isUserProvided())
data().HasTrivialMoveAssignment = false;
- }
}
// Keep the list of conversion functions up-to-date.
@@ -667,6 +690,10 @@ void CXXRecordDecl::addedMember(Decl *D) {
data().HasPublicFields) > 1)
data().IsStandardLayout = false;
+ // Keep track of the presence of mutable fields.
+ if (Field->isMutable())
+ data().HasMutableFields = true;
+
// C++0x [class]p9:
// A POD struct is a class that is both a trivial class and a
// standard-layout class, and has no non-static data members of type
@@ -676,7 +703,7 @@ void CXXRecordDecl::addedMember(Decl *D) {
if (!T->isPODType())
data().PlainOldData = false;
if (T->isReferenceType()) {
- data().HasTrivialConstructor = false;
+ data().HasTrivialDefaultConstructor = false;
// C++0x [class]p7:
// A standard-layout class is a class that:
@@ -688,11 +715,32 @@ void CXXRecordDecl::addedMember(Decl *D) {
if (!hasNonLiteralTypeFieldsOrBases() && !T->isLiteralType())
data().HasNonLiteralTypeFieldsOrBases = true;
+ if (Field->hasInClassInitializer()) {
+ // C++0x [class]p5:
+ // A default constructor is trivial if [...] no non-static data member
+ // of its class has a brace-or-equal-initializer.
+ data().HasTrivialDefaultConstructor = false;
+
+ // C++0x [dcl.init.aggr]p1:
+ // An aggregate is a [...] class with [...] no
+ // brace-or-equal-initializers for non-static data members.
+ data().Aggregate = false;
+
+ // C++0x [class]p10:
+ // A POD struct is [...] a trivial class.
+ data().PlainOldData = false;
+ }
+
if (const RecordType *RecordTy = T->getAs<RecordType>()) {
CXXRecordDecl* FieldRec = cast<CXXRecordDecl>(RecordTy->getDecl());
if (FieldRec->getDefinition()) {
- if (!FieldRec->hasTrivialConstructor())
- data().HasTrivialConstructor = false;
+ // C++0x [class.ctor]p5:
+ // A defulat constructor is trivial [...] if:
+ // -- for all the non-static data members of its class that are of
+ // class type (or array thereof), each such class has a trivial
+ // default constructor.
+ if (!FieldRec->hasTrivialDefaultConstructor())
+ data().HasTrivialDefaultConstructor = false;
// C++0x [class.copy]p13:
// A copy/move constructor for class X is trivial if [...]
@@ -753,6 +801,10 @@ void CXXRecordDecl::addedMember(Decl *D) {
}
}
}
+
+ // Keep track of the presence of mutable fields.
+ if (FieldRec->hasMutableFields())
+ data().HasMutableFields = true;
}
}
@@ -1135,14 +1187,13 @@ bool CXXMethodDecl::isUsualDeallocationFunction() const {
}
bool CXXMethodDecl::isCopyAssignmentOperator() const {
- // C++0x [class.copy]p19:
+ // C++0x [class.copy]p17:
// A user-declared copy assignment operator X::operator= is a non-static
// non-template member function of class X with exactly one parameter of
// type X, X&, const X&, volatile X& or const volatile X&.
if (/*operator=*/getOverloadedOperator() != OO_Equal ||
/*non-static*/ isStatic() ||
- /*non-template*/getPrimaryTemplate() || getDescribedFunctionTemplate() ||
- /*exactly one parameter*/getNumParams() != 1)
+ /*non-template*/getPrimaryTemplate() || getDescribedFunctionTemplate())
return false;
QualType ParamType = getParamDecl(0)->getType();
@@ -1155,6 +1206,26 @@ bool CXXMethodDecl::isCopyAssignmentOperator() const {
return Context.hasSameUnqualifiedType(ClassType, ParamType);
}
+bool CXXMethodDecl::isMoveAssignmentOperator() const {
+ // C++0x [class.copy]p19:
+ // A user-declared move assignment operator X::operator= is a non-static
+ // non-template member function of class X with exactly one parameter of type
+ // X&&, const X&&, volatile X&&, or const volatile X&&.
+ if (getOverloadedOperator() != OO_Equal || isStatic() ||
+ getPrimaryTemplate() || getDescribedFunctionTemplate())
+ return false;
+
+ QualType ParamType = getParamDecl(0)->getType();
+ if (!isa<RValueReferenceType>(ParamType))
+ return false;
+ ParamType = ParamType->getPointeeType();
+
+ ASTContext &Context = getASTContext();
+ QualType ClassType
+ = Context.getCanonicalType(Context.getTypeDeclType(getParent()));
+ return Context.hasSameUnqualifiedType(ClassType, ParamType);
+}
+
void CXXMethodDecl::addOverriddenMethod(const CXXMethodDecl *MD) {
assert(MD->isCanonicalDecl() && "Method is not canonical!");
assert(!MD->getParent()->isDependentContext() &&
@@ -1290,11 +1361,21 @@ const Type *CXXCtorInitializer::getBaseClass() const {
SourceLocation CXXCtorInitializer::getSourceLocation() const {
if (isAnyMemberInitializer() || isDelegatingInitializer())
return getMemberLocation();
+
+ if (isInClassMemberInitializer())
+ return getAnyMember()->getLocation();
return getBaseClassLoc().getLocalSourceRange().getBegin();
}
SourceRange CXXCtorInitializer::getSourceRange() const {
+ if (isInClassMemberInitializer()) {
+ FieldDecl *D = getAnyMember();
+ if (Expr *I = D->getInClassInitializer())
+ return I->getSourceRange();
+ return SourceRange();
+ }
+
return SourceRange(getSourceLocation(), getRParenLoc());
}
diff --git a/lib/AST/DeclObjC.cpp b/lib/AST/DeclObjC.cpp
index 24d281e..e2c4f38 100644
--- a/lib/AST/DeclObjC.cpp
+++ b/lib/AST/DeclObjC.cpp
@@ -339,12 +339,14 @@ ObjCMethodDecl *ObjCMethodDecl::Create(ASTContext &C,
bool isSynthesized,
bool isDefined,
ImplementationControl impControl,
+ bool HasRelatedResultType,
unsigned numSelectorArgs) {
return new (C) ObjCMethodDecl(beginLoc, endLoc,
SelInfo, T, ResultTInfo, contextDecl,
isInstance,
isVariadic, isSynthesized, isDefined,
impControl,
+ HasRelatedResultType,
numSelectorArgs);
}
@@ -446,6 +448,7 @@ ObjCMethodFamily ObjCMethodDecl::getMethodFamily() const {
case OMF_release:
case OMF_autorelease:
case OMF_retainCount:
+ case OMF_self:
if (!isInstanceMethod())
family = OMF_None;
break;
diff --git a/lib/AST/DeclPrinter.cpp b/lib/AST/DeclPrinter.cpp
index 2fd88d7..421770e 100644
--- a/lib/AST/DeclPrinter.cpp
+++ b/lib/AST/DeclPrinter.cpp
@@ -400,7 +400,7 @@ void DeclPrinter::VisitFunctionDecl(FunctionDecl *D) {
if (D->getNumParams()) POut << ", ";
POut << "...";
}
- } else if (D->isThisDeclarationADefinition() && !D->hasPrototype()) {
+ } else if (D->doesThisDeclarationHaveABody() && !D->hasPrototype()) {
for (unsigned i = 0, e = D->getNumParams(); i != e; ++i) {
if (i)
Proto += ", ";
@@ -450,62 +450,67 @@ void DeclPrinter::VisitFunctionDecl(FunctionDecl *D) {
if (D->hasAttr<NoReturnAttr>())
Proto += " __attribute((noreturn))";
if (CXXConstructorDecl *CDecl = dyn_cast<CXXConstructorDecl>(D)) {
- if (CDecl->getNumCtorInitializers() > 0) {
- Proto += " : ";
- Out << Proto;
- Proto.clear();
- for (CXXConstructorDecl::init_const_iterator B = CDecl->init_begin(),
- E = CDecl->init_end();
- B != E; ++B) {
- CXXCtorInitializer * BMInitializer = (*B);
- if (B != CDecl->init_begin())
- Out << ", ";
- if (BMInitializer->isAnyMemberInitializer()) {
- FieldDecl *FD = BMInitializer->getAnyMember();
- Out << FD;
- } else {
- Out << QualType(BMInitializer->getBaseClass(),
- 0).getAsString(Policy);
- }
+ bool HasInitializerList = false;
+ for (CXXConstructorDecl::init_const_iterator B = CDecl->init_begin(),
+ E = CDecl->init_end();
+ B != E; ++B) {
+ CXXCtorInitializer * BMInitializer = (*B);
+ if (BMInitializer->isInClassMemberInitializer())
+ continue;
+
+ if (!HasInitializerList) {
+ Proto += " : ";
+ Out << Proto;
+ Proto.clear();
+ HasInitializerList = true;
+ } else
+ Out << ", ";
+
+ if (BMInitializer->isAnyMemberInitializer()) {
+ FieldDecl *FD = BMInitializer->getAnyMember();
+ Out << FD;
+ } else {
+ Out << QualType(BMInitializer->getBaseClass(),
+ 0).getAsString(Policy);
+ }
+
+ Out << "(";
+ if (!BMInitializer->getInit()) {
+ // Nothing to print
+ } else {
+ Expr *Init = BMInitializer->getInit();
+ if (ExprWithCleanups *Tmp = dyn_cast<ExprWithCleanups>(Init))
+ Init = Tmp->getSubExpr();
+
+ Init = Init->IgnoreParens();
- Out << "(";
- if (!BMInitializer->getInit()) {
- // Nothing to print
- } else {
- Expr *Init = BMInitializer->getInit();
- if (ExprWithCleanups *Tmp = dyn_cast<ExprWithCleanups>(Init))
- Init = Tmp->getSubExpr();
-
- Init = Init->IgnoreParens();
-
- Expr *SimpleInit = 0;
- Expr **Args = 0;
- unsigned NumArgs = 0;
- if (ParenListExpr *ParenList = dyn_cast<ParenListExpr>(Init)) {
- Args = ParenList->getExprs();
- NumArgs = ParenList->getNumExprs();
- } else if (CXXConstructExpr *Construct
- = dyn_cast<CXXConstructExpr>(Init)) {
- Args = Construct->getArgs();
- NumArgs = Construct->getNumArgs();
- } else
- SimpleInit = Init;
-
- if (SimpleInit)
- SimpleInit->printPretty(Out, Context, 0, Policy, Indentation);
- else {
- for (unsigned I = 0; I != NumArgs; ++I) {
- if (isa<CXXDefaultArgExpr>(Args[I]))
- break;
-
- if (I)
- Out << ", ";
- Args[I]->printPretty(Out, Context, 0, Policy, Indentation);
- }
+ Expr *SimpleInit = 0;
+ Expr **Args = 0;
+ unsigned NumArgs = 0;
+ if (ParenListExpr *ParenList = dyn_cast<ParenListExpr>(Init)) {
+ Args = ParenList->getExprs();
+ NumArgs = ParenList->getNumExprs();
+ } else if (CXXConstructExpr *Construct
+ = dyn_cast<CXXConstructExpr>(Init)) {
+ Args = Construct->getArgs();
+ NumArgs = Construct->getNumArgs();
+ } else
+ SimpleInit = Init;
+
+ if (SimpleInit)
+ SimpleInit->printPretty(Out, Context, 0, Policy, Indentation);
+ else {
+ for (unsigned I = 0; I != NumArgs; ++I) {
+ if (isa<CXXDefaultArgExpr>(Args[I]))
+ break;
+
+ if (I)
+ Out << ", ";
+ Args[I]->printPretty(Out, Context, 0, Policy, Indentation);
}
}
- Out << ")";
}
+ Out << ")";
}
}
else
@@ -518,9 +523,9 @@ void DeclPrinter::VisitFunctionDecl(FunctionDecl *D) {
if (D->isPure())
Out << " = 0";
- else if (D->isDeleted())
+ else if (D->isDeletedAsWritten())
Out << " = delete";
- else if (D->isThisDeclarationADefinition()) {
+ else if (D->doesThisDeclarationHaveABody()) {
if (!D->hasPrototype() && D->getNumParams()) {
// This is a K&R function definition, so we need to print the
// parameters.
@@ -553,6 +558,12 @@ void DeclPrinter::VisitFieldDecl(FieldDecl *D) {
Out << " : ";
D->getBitWidth()->printPretty(Out, Context, 0, Policy, Indentation);
}
+
+ Expr *Init = D->getInClassInitializer();
+ if (!Policy.SuppressInitializers && Init) {
+ Out << " = ";
+ Init->printPretty(Out, Context, 0, Policy, Indentation);
+ }
}
void DeclPrinter::VisitLabelDecl(LabelDecl *D) {
@@ -932,6 +943,11 @@ void DeclPrinter::VisitObjCPropertyDecl(ObjCPropertyDecl *PDecl) {
Out << (first ? ' ' : ',') << "nonatomic";
first = false;
}
+ if (PDecl->getPropertyAttributes() &
+ ObjCPropertyDecl::OBJC_PR_atomic) {
+ Out << (first ? ' ' : ',') << "atomic";
+ first = false;
+ }
Out << " )";
}
Out << ' ' << PDecl->getType().getAsString(Policy) << ' ' << PDecl;
diff --git a/lib/AST/DeclTemplate.cpp b/lib/AST/DeclTemplate.cpp
index 6272340..bc375d0a 100644
--- a/lib/AST/DeclTemplate.cpp
+++ b/lib/AST/DeclTemplate.cpp
@@ -735,3 +735,34 @@ FriendTemplateDecl *FriendTemplateDecl::Create(ASTContext &Context,
EmptyShell Empty) {
return new (Context) FriendTemplateDecl(Empty);
}
+
+//===----------------------------------------------------------------------===//
+// TypeAliasTemplateDecl Implementation
+//===----------------------------------------------------------------------===//
+
+TypeAliasTemplateDecl *TypeAliasTemplateDecl::Create(ASTContext &C,
+ DeclContext *DC,
+ SourceLocation L,
+ DeclarationName Name,
+ TemplateParameterList *Params,
+ NamedDecl *Decl) {
+ AdoptTemplateParameterList(Params, DC);
+ return new (C) TypeAliasTemplateDecl(DC, L, Name, Params, Decl);
+}
+
+TypeAliasTemplateDecl *TypeAliasTemplateDecl::Create(ASTContext &C,
+ EmptyShell) {
+ return new (C) TypeAliasTemplateDecl(0, SourceLocation(), DeclarationName(),
+ 0, 0);
+}
+
+void TypeAliasTemplateDecl::DeallocateCommon(void *Ptr) {
+ static_cast<Common *>(Ptr)->~Common();
+}
+RedeclarableTemplateDecl::CommonBase *
+TypeAliasTemplateDecl::newCommon(ASTContext &C) {
+ Common *CommonPtr = new (C) Common;
+ C.AddDeallocation(DeallocateCommon, CommonPtr);
+ return CommonPtr;
+}
+
diff --git a/lib/AST/DumpXML.cpp b/lib/AST/DumpXML.cpp
index 7d593bc..dfe0119 100644
--- a/lib/AST/DumpXML.cpp
+++ b/lib/AST/DumpXML.cpp
@@ -482,18 +482,20 @@ struct XMLDumper : public XMLDeclVisitor<XMLDumper>,
setFlag("trivial", D->isTrivial());
setFlag("returnzero", D->hasImplicitReturnZero());
setFlag("prototype", D->hasWrittenPrototype());
- setFlag("deleted", D->isDeleted());
+ setFlag("deleted", D->isDeletedAsWritten());
if (D->getStorageClass() != SC_None)
set("storage",
VarDecl::getStorageClassSpecifierString(D->getStorageClass()));
setFlag("inline", D->isInlineSpecified());
+ if (const AsmLabelAttr *ALA = D->getAttr<AsmLabelAttr>())
+ set("asmlabel", ALA->getLabel());
// TODO: instantiation, etc.
}
void visitFunctionDeclChildren(FunctionDecl *D) {
for (FunctionDecl::param_iterator
I = D->param_begin(), E = D->param_end(); I != E; ++I)
dispatch(*I);
- if (D->isThisDeclarationADefinition())
+ if (D->doesThisDeclarationHaveABody())
dispatch(D->getBody());
}
@@ -619,7 +621,8 @@ struct XMLDumper : public XMLDeclVisitor<XMLDumper>,
// TemplateDecl
void visitTemplateDeclChildren(TemplateDecl *D) {
visitTemplateParameters(D->getTemplateParameters());
- dispatch(D->getTemplatedDecl());
+ if (D->getTemplatedDecl())
+ dispatch(D->getTemplatedDecl());
}
// FunctionTemplateDecl
@@ -845,6 +848,7 @@ struct XMLDumper : public XMLDeclVisitor<XMLDumper>,
setFlag("variadic", D->isVariadic());
setFlag("synthesized", D->isSynthesized());
setFlag("defined", D->isDefined());
+ setFlag("related_result_type", D->hasRelatedResultType());
}
void visitObjCMethodDeclChildren(ObjCMethodDecl *D) {
dispatch(D->getResultType());
diff --git a/lib/AST/Expr.cpp b/lib/AST/Expr.cpp
index 6499f32..9872139 100644
--- a/lib/AST/Expr.cpp
+++ b/lib/AST/Expr.cpp
@@ -22,6 +22,7 @@
#include "clang/AST/StmtVisitor.h"
#include "clang/Lex/LiteralSupport.h"
#include "clang/Lex/Lexer.h"
+#include "clang/Sema/SemaDiagnostic.h"
#include "clang/Basic/Builtins.h"
#include "clang/Basic/SourceManager.h"
#include "clang/Basic/TargetInfo.h"
@@ -1653,7 +1654,8 @@ static Expr::CanThrowResult CanSubExprsThrow(ASTContext &C, const Expr *CE) {
return R;
}
-static Expr::CanThrowResult CanCalleeThrow(ASTContext &Ctx, const Decl *D,
+static Expr::CanThrowResult CanCalleeThrow(ASTContext &Ctx, const Expr *E,
+ const Decl *D,
bool NullThrows = true) {
if (!D)
return NullThrows ? Expr::CT_Can : Expr::CT_Cannot;
@@ -1683,6 +1685,15 @@ static Expr::CanThrowResult CanCalleeThrow(ASTContext &Ctx, const Decl *D,
if (!FT)
return Expr::CT_Can;
+ if (FT->getExceptionSpecType() == EST_Delayed) {
+ assert(isa<CXXConstructorDecl>(D) &&
+ "only constructor exception specs can be unknown");
+ Ctx.getDiagnostics().Report(E->getLocStart(),
+ diag::err_exception_spec_unknown)
+ << E->getSourceRange();
+ return Expr::CT_Can;
+ }
+
return FT->isNothrow(Ctx) ? Expr::CT_Cannot : Expr::CT_Can;
}
@@ -1693,6 +1704,9 @@ static Expr::CanThrowResult CanDynamicCastThrow(const CXXDynamicCastExpr *DC) {
if (!DC->getTypeAsWritten()->isReferenceType())
return Expr::CT_Cannot;
+ if (DC->getSubExpr()->isTypeDependent())
+ return Expr::CT_Dependent;
+
return DC->getCastKind() == clang::CK_Dynamic? Expr::CT_Can : Expr::CT_Cannot;
}
@@ -1747,7 +1761,14 @@ Expr::CanThrowResult Expr::CanThrow(ASTContext &C) const {
case CallExprClass:
case CXXOperatorCallExprClass:
case CXXMemberCallExprClass: {
- CanThrowResult CT = CanCalleeThrow(C,cast<CallExpr>(this)->getCalleeDecl());
+ const CallExpr *CE = cast<CallExpr>(this);
+ CanThrowResult CT;
+ if (isTypeDependent())
+ CT = CT_Dependent;
+ else if (isa<CXXPseudoDestructorExpr>(CE->getCallee()->IgnoreParens()))
+ CT = CT_Cannot;
+ else
+ CT = CanCalleeThrow(C, this, CE->getCalleeDecl());
if (CT == CT_Can)
return CT;
return MergeCanThrow(CT, CanSubExprsThrow(C, this));
@@ -1755,7 +1776,7 @@ Expr::CanThrowResult Expr::CanThrow(ASTContext &C) const {
case CXXConstructExprClass:
case CXXTemporaryObjectExprClass: {
- CanThrowResult CT = CanCalleeThrow(C,
+ CanThrowResult CT = CanCalleeThrow(C, this,
cast<CXXConstructExpr>(this)->getConstructor());
if (CT == CT_Can)
return CT;
@@ -1763,9 +1784,13 @@ Expr::CanThrowResult Expr::CanThrow(ASTContext &C) const {
}
case CXXNewExprClass: {
- CanThrowResult CT = MergeCanThrow(
- CanCalleeThrow(C, cast<CXXNewExpr>(this)->getOperatorNew()),
- CanCalleeThrow(C, cast<CXXNewExpr>(this)->getConstructor(),
+ CanThrowResult CT;
+ if (isTypeDependent())
+ CT = CT_Dependent;
+ else
+ CT = MergeCanThrow(
+ CanCalleeThrow(C, this, cast<CXXNewExpr>(this)->getOperatorNew()),
+ CanCalleeThrow(C, this, cast<CXXNewExpr>(this)->getConstructor(),
/*NullThrows*/false));
if (CT == CT_Can)
return CT;
@@ -1773,29 +1798,26 @@ Expr::CanThrowResult Expr::CanThrow(ASTContext &C) const {
}
case CXXDeleteExprClass: {
- CanThrowResult CT = CanCalleeThrow(C,
- cast<CXXDeleteExpr>(this)->getOperatorDelete());
- if (CT == CT_Can)
- return CT;
- const Expr *Arg = cast<CXXDeleteExpr>(this)->getArgument();
- // Unwrap exactly one implicit cast, which converts all pointers to void*.
- if (const ImplicitCastExpr *Cast = dyn_cast<ImplicitCastExpr>(Arg))
- Arg = Cast->getSubExpr();
- if (const PointerType *PT = Arg->getType()->getAs<PointerType>()) {
- if (const RecordType *RT = PT->getPointeeType()->getAs<RecordType>()) {
- CanThrowResult CT2 = CanCalleeThrow(C,
- cast<CXXRecordDecl>(RT->getDecl())->getDestructor());
- if (CT2 == CT_Can)
- return CT2;
- CT = MergeCanThrow(CT, CT2);
+ CanThrowResult CT;
+ QualType DTy = cast<CXXDeleteExpr>(this)->getDestroyedType();
+ if (DTy.isNull() || DTy->isDependentType()) {
+ CT = CT_Dependent;
+ } else {
+ CT = CanCalleeThrow(C, this,
+ cast<CXXDeleteExpr>(this)->getOperatorDelete());
+ if (const RecordType *RT = DTy->getAs<RecordType>()) {
+ const CXXRecordDecl *RD = cast<CXXRecordDecl>(RT->getDecl());
+ CT = MergeCanThrow(CT, CanCalleeThrow(C, this, RD->getDestructor()));
}
+ if (CT == CT_Can)
+ return CT;
}
return MergeCanThrow(CT, CanSubExprsThrow(C, this));
}
case CXXBindTemporaryExprClass: {
// The bound temporary has to be destroyed again, which might throw.
- CanThrowResult CT = CanCalleeThrow(C,
+ CanThrowResult CT = CanCalleeThrow(C, this,
cast<CXXBindTemporaryExpr>(this)->getTemporary()->getDestructor());
if (CT == CT_Can)
return CT;
@@ -1978,6 +2000,14 @@ Expr *Expr::IgnoreParenImpCasts() {
}
}
+Expr *Expr::IgnoreConversionOperator() {
+ if (CXXMemberCallExpr *MCE = dyn_cast<CXXMemberCallExpr>(this)) {
+ if (isa<CXXConversionDecl>(MCE->getMethodDecl()))
+ return MCE->getImplicitObjectArgument();
+ }
+ return this;
+}
+
/// 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.
@@ -3013,4 +3043,3 @@ BlockDeclRefExpr::BlockDeclRefExpr(VarDecl *d, QualType t, ExprValueKind VK,
ExprBits.TypeDependent = TypeDependent;
ExprBits.ValueDependent = ValueDependent;
}
-
diff --git a/lib/AST/ExprClassification.cpp b/lib/AST/ExprClassification.cpp
index 888a93c..d177cb5 100644
--- a/lib/AST/ExprClassification.cpp
+++ b/lib/AST/ExprClassification.cpp
@@ -161,6 +161,7 @@ static Cl::Kinds ClassifyInternal(ASTContext &Ctx, const Expr *E) {
case Expr::InitListExprClass:
case Expr::SizeOfPackExprClass:
case Expr::SubstNonTypeTemplateParmPackExprClass:
+ case Expr::AsTypeExprClass:
return Cl::CL_PRValue;
// Next come the complicated cases.
@@ -465,14 +466,16 @@ static Cl::Kinds ClassifyBinaryOp(ASTContext &Ctx, const BinaryOperator *E) {
// is a pointer to a data member is of the same value category as its first
// operand.
if (E->getOpcode() == BO_PtrMemD)
- return E->getType()->isFunctionType() ? Cl::CL_MemberFunction :
- ClassifyInternal(Ctx, E->getLHS());
+ return (E->getType()->isFunctionType() || E->getType() == Ctx.BoundMemberTy)
+ ? Cl::CL_MemberFunction
+ : ClassifyInternal(Ctx, E->getLHS());
// C++ [expr.mptr.oper]p6: The result of an ->* expression is an lvalue if its
// second operand is a pointer to data member and a prvalue otherwise.
if (E->getOpcode() == BO_PtrMemI)
- return E->getType()->isFunctionType() ?
- Cl::CL_MemberFunction : Cl::CL_LValue;
+ return (E->getType()->isFunctionType() || E->getType() == Ctx.BoundMemberTy)
+ ? Cl::CL_MemberFunction
+ : Cl::CL_LValue;
// All other binary operations are prvalues.
return Cl::CL_PRValue;
diff --git a/lib/AST/ExprConstant.cpp b/lib/AST/ExprConstant.cpp
index c2caf8d4..06c5645 100644
--- a/lib/AST/ExprConstant.cpp
+++ b/lib/AST/ExprConstant.cpp
@@ -102,10 +102,10 @@ namespace {
};
struct LValue {
- Expr *Base;
+ const Expr *Base;
CharUnits Offset;
- Expr *getLValueBase() { return Base; }
+ const Expr *getLValueBase() { return Base; }
CharUnits getLValueOffset() { return Offset; }
void moveInto(APValue &v) const {
@@ -221,7 +221,7 @@ static APSInt HandleFloatToIntCast(QualType DestType, QualType SrcType,
APFloat &Value, const ASTContext &Ctx) {
unsigned DestWidth = Ctx.getIntWidth(DestType);
// Determine whether we are converting to unsigned or signed.
- bool DestSigned = DestType->isSignedIntegerType();
+ bool DestSigned = DestType->isSignedIntegerOrEnumerationType();
// FIXME: Warning for overflow.
uint64_t Space[4];
@@ -247,7 +247,7 @@ static APSInt HandleIntToIntCast(QualType DestType, QualType SrcType,
// Figure out if this is a truncate, extend or noop cast.
// If the input is signed, do a sign extend, noop, or truncate.
Result = Result.extOrTrunc(DestWidth);
- Result.setIsUnsigned(DestType->isUnsignedIntegerType());
+ Result.setIsUnsigned(DestType->isUnsignedIntegerOrEnumerationType());
return Result;
}
@@ -262,69 +262,69 @@ static APFloat HandleIntToFloatCast(QualType DestType, QualType SrcType,
namespace {
class HasSideEffect
- : public StmtVisitor<HasSideEffect, bool> {
+ : public ConstStmtVisitor<HasSideEffect, bool> {
EvalInfo &Info;
public:
HasSideEffect(EvalInfo &info) : Info(info) {}
// Unhandled nodes conservatively default to having side effects.
- bool VisitStmt(Stmt *S) {
+ bool VisitStmt(const Stmt *S) {
return true;
}
- bool VisitParenExpr(ParenExpr *E) { return Visit(E->getSubExpr()); }
- bool VisitGenericSelectionExpr(GenericSelectionExpr *E) {
+ bool VisitParenExpr(const ParenExpr *E) { return Visit(E->getSubExpr()); }
+ bool VisitGenericSelectionExpr(const GenericSelectionExpr *E) {
return Visit(E->getResultExpr());
}
- bool VisitDeclRefExpr(DeclRefExpr *E) {
+ bool VisitDeclRefExpr(const DeclRefExpr *E) {
if (Info.Ctx.getCanonicalType(E->getType()).isVolatileQualified())
return true;
return false;
}
// We don't want to evaluate BlockExprs multiple times, as they generate
// a ton of code.
- bool VisitBlockExpr(BlockExpr *E) { return true; }
- bool VisitPredefinedExpr(PredefinedExpr *E) { return false; }
- bool VisitCompoundLiteralExpr(CompoundLiteralExpr *E)
+ bool VisitBlockExpr(const BlockExpr *E) { return true; }
+ bool VisitPredefinedExpr(const PredefinedExpr *E) { return false; }
+ bool VisitCompoundLiteralExpr(const CompoundLiteralExpr *E)
{ return Visit(E->getInitializer()); }
- bool VisitMemberExpr(MemberExpr *E) { return Visit(E->getBase()); }
- bool VisitIntegerLiteral(IntegerLiteral *E) { return false; }
- bool VisitFloatingLiteral(FloatingLiteral *E) { return false; }
- bool VisitStringLiteral(StringLiteral *E) { return false; }
- bool VisitCharacterLiteral(CharacterLiteral *E) { return false; }
- bool VisitUnaryExprOrTypeTraitExpr(UnaryExprOrTypeTraitExpr *E)
+ bool VisitMemberExpr(const MemberExpr *E) { return Visit(E->getBase()); }
+ bool VisitIntegerLiteral(const IntegerLiteral *E) { return false; }
+ bool VisitFloatingLiteral(const FloatingLiteral *E) { return false; }
+ bool VisitStringLiteral(const StringLiteral *E) { return false; }
+ bool VisitCharacterLiteral(const CharacterLiteral *E) { return false; }
+ bool VisitUnaryExprOrTypeTraitExpr(const UnaryExprOrTypeTraitExpr *E)
{ return false; }
- bool VisitArraySubscriptExpr(ArraySubscriptExpr *E)
+ bool VisitArraySubscriptExpr(const ArraySubscriptExpr *E)
{ return Visit(E->getLHS()) || Visit(E->getRHS()); }
- bool VisitChooseExpr(ChooseExpr *E)
+ bool VisitChooseExpr(const ChooseExpr *E)
{ return Visit(E->getChosenSubExpr(Info.Ctx)); }
- bool VisitCastExpr(CastExpr *E) { return Visit(E->getSubExpr()); }
- bool VisitBinAssign(BinaryOperator *E) { return true; }
- bool VisitCompoundAssignOperator(BinaryOperator *E) { return true; }
- bool VisitBinaryOperator(BinaryOperator *E)
+ bool VisitCastExpr(const CastExpr *E) { return Visit(E->getSubExpr()); }
+ bool VisitBinAssign(const BinaryOperator *E) { return true; }
+ bool VisitCompoundAssignOperator(const BinaryOperator *E) { return true; }
+ bool VisitBinaryOperator(const BinaryOperator *E)
{ return Visit(E->getLHS()) || Visit(E->getRHS()); }
- bool VisitUnaryPreInc(UnaryOperator *E) { return true; }
- bool VisitUnaryPostInc(UnaryOperator *E) { return true; }
- bool VisitUnaryPreDec(UnaryOperator *E) { return true; }
- bool VisitUnaryPostDec(UnaryOperator *E) { return true; }
- bool VisitUnaryDeref(UnaryOperator *E) {
+ bool VisitUnaryPreInc(const UnaryOperator *E) { return true; }
+ bool VisitUnaryPostInc(const UnaryOperator *E) { return true; }
+ bool VisitUnaryPreDec(const UnaryOperator *E) { return true; }
+ bool VisitUnaryPostDec(const UnaryOperator *E) { return true; }
+ bool VisitUnaryDeref(const UnaryOperator *E) {
if (Info.Ctx.getCanonicalType(E->getType()).isVolatileQualified())
return true;
return Visit(E->getSubExpr());
}
- bool VisitUnaryOperator(UnaryOperator *E) { return Visit(E->getSubExpr()); }
+ bool VisitUnaryOperator(const UnaryOperator *E) { return Visit(E->getSubExpr()); }
// Has side effects if any element does.
- bool VisitInitListExpr(InitListExpr *E) {
+ bool VisitInitListExpr(const InitListExpr *E) {
for (unsigned i = 0, e = E->getNumInits(); i != e; ++i)
if (Visit(E->getInit(i))) return true;
- if (Expr *filler = E->getArrayFiller())
+ if (const Expr *filler = E->getArrayFiller())
return Visit(filler);
return false;
}
- bool VisitSizeOfPackExpr(SizeOfPackExpr *) { return false; }
+ bool VisitSizeOfPackExpr(const SizeOfPackExpr *) { return false; }
};
class OpaqueValueEvaluation {
@@ -354,15 +354,89 @@ public:
} // end anonymous namespace
//===----------------------------------------------------------------------===//
+// Generic Evaluation
+//===----------------------------------------------------------------------===//
+namespace {
+
+template <class Derived, typename RetTy=void>
+class ExprEvaluatorBase
+ : public ConstStmtVisitor<Derived, RetTy> {
+private:
+ RetTy DerivedSuccess(const APValue &V, const Expr *E) {
+ return static_cast<Derived*>(this)->Success(V, E);
+ }
+ RetTy DerivedError(const Expr *E) {
+ return static_cast<Derived*>(this)->Error(E);
+ }
+
+protected:
+ EvalInfo &Info;
+ typedef ConstStmtVisitor<Derived, RetTy> StmtVisitorTy;
+ typedef ExprEvaluatorBase ExprEvaluatorBaseTy;
+
+public:
+ ExprEvaluatorBase(EvalInfo &Info) : Info(Info) {}
+
+ RetTy VisitStmt(const Stmt *) {
+ assert(0 && "Expression evaluator should not be called on stmts");
+ return DerivedError(0);
+ }
+ RetTy VisitExpr(const Expr *E) {
+ return DerivedError(E);
+ }
+
+ RetTy VisitParenExpr(const ParenExpr *E)
+ { return StmtVisitorTy::Visit(E->getSubExpr()); }
+ RetTy VisitUnaryExtension(const UnaryOperator *E)
+ { return StmtVisitorTy::Visit(E->getSubExpr()); }
+ RetTy VisitUnaryPlus(const UnaryOperator *E)
+ { return StmtVisitorTy::Visit(E->getSubExpr()); }
+ RetTy VisitChooseExpr(const ChooseExpr *E)
+ { return StmtVisitorTy::Visit(E->getChosenSubExpr(Info.Ctx)); }
+ RetTy VisitGenericSelectionExpr(const GenericSelectionExpr *E)
+ { return StmtVisitorTy::Visit(E->getResultExpr()); }
+
+ RetTy VisitBinaryConditionalOperator(const BinaryConditionalOperator *E) {
+ OpaqueValueEvaluation opaque(Info, E->getOpaqueValue(), E->getCommon());
+ if (opaque.hasError())
+ return DerivedError(E);
+
+ bool cond;
+ if (!HandleConversionToBool(E->getCond(), cond, Info))
+ return DerivedError(E);
+
+ return StmtVisitorTy::Visit(cond ? E->getTrueExpr() : E->getFalseExpr());
+ }
+
+ RetTy VisitConditionalOperator(const ConditionalOperator *E) {
+ bool BoolResult;
+ if (!HandleConversionToBool(E->getCond(), BoolResult, Info))
+ return DerivedError(E);
+
+ Expr* EvalExpr = BoolResult ? E->getTrueExpr() : E->getFalseExpr();
+ return StmtVisitorTy::Visit(EvalExpr);
+ }
+
+ RetTy VisitOpaqueValueExpr(const OpaqueValueExpr *E) {
+ const APValue *value = Info.getOpaqueValue(E);
+ if (!value)
+ return (E->getSourceExpr() ? StmtVisitorTy::Visit(E->getSourceExpr())
+ : DerivedError(E));
+ return DerivedSuccess(*value, E);
+ }
+};
+
+}
+
+//===----------------------------------------------------------------------===//
// LValue Evaluation
//===----------------------------------------------------------------------===//
namespace {
class LValueExprEvaluator
- : public StmtVisitor<LValueExprEvaluator, bool> {
- EvalInfo &Info;
+ : public ExprEvaluatorBase<LValueExprEvaluator, bool> {
LValue &Result;
- bool Success(Expr *E) {
+ bool Success(const Expr *E) {
Result.Base = E;
Result.Offset = CharUnits::Zero();
return true;
@@ -370,30 +444,26 @@ class LValueExprEvaluator
public:
LValueExprEvaluator(EvalInfo &info, LValue &Result) :
- Info(info), Result(Result) {}
+ ExprEvaluatorBaseTy(info), Result(Result) {}
- bool VisitStmt(Stmt *S) {
+ bool Success(const APValue &V, const Expr *E) {
+ Result.setFrom(V);
+ return true;
+ }
+ bool Error(const Expr *E) {
return false;
}
- bool VisitParenExpr(ParenExpr *E) { return Visit(E->getSubExpr()); }
- bool VisitGenericSelectionExpr(GenericSelectionExpr *E) {
- return Visit(E->getResultExpr());
- }
- 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()); }
- bool VisitChooseExpr(const ChooseExpr *E)
- { return Visit(E->getChosenSubExpr(Info.Ctx)); }
-
- bool VisitCastExpr(CastExpr *E) {
+ bool VisitDeclRefExpr(const DeclRefExpr *E);
+ bool VisitPredefinedExpr(const PredefinedExpr *E) { return Success(E); }
+ bool VisitCompoundLiteralExpr(const CompoundLiteralExpr *E);
+ bool VisitMemberExpr(const MemberExpr *E);
+ bool VisitStringLiteral(const StringLiteral *E) { return Success(E); }
+ bool VisitObjCEncodeExpr(const ObjCEncodeExpr *E) { return Success(E); }
+ bool VisitArraySubscriptExpr(const ArraySubscriptExpr *E);
+ bool VisitUnaryDeref(const UnaryOperator *E);
+
+ bool VisitCastExpr(const CastExpr *E) {
switch (E->getCastKind()) {
default:
return false;
@@ -403,36 +473,37 @@ public:
}
}
// FIXME: Missing: __real__, __imag__
+
};
} // end anonymous namespace
static bool EvaluateLValue(const Expr* E, LValue& Result, EvalInfo &Info) {
- return LValueExprEvaluator(Info, Result).Visit(const_cast<Expr*>(E));
+ return LValueExprEvaluator(Info, Result).Visit(E);
}
-bool LValueExprEvaluator::VisitDeclRefExpr(DeclRefExpr *E) {
+bool LValueExprEvaluator::VisitDeclRefExpr(const DeclRefExpr *E) {
if (isa<FunctionDecl>(E->getDecl())) {
return Success(E);
- } else if (VarDecl* VD = dyn_cast<VarDecl>(E->getDecl())) {
+ } else if (const VarDecl* VD = dyn_cast<VarDecl>(E->getDecl())) {
if (!VD->getType()->isReferenceType())
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));
+ if (!isa<ParmVarDecl>(VD))
+ // FIXME: Check whether VD might be overridden!
+ if (const Expr *Init = VD->getAnyInitializer())
+ return Visit(Init);
}
- return false;
+ return ExprEvaluatorBaseTy::VisitDeclRefExpr(E);
}
-bool LValueExprEvaluator::VisitCompoundLiteralExpr(CompoundLiteralExpr *E) {
+bool
+LValueExprEvaluator::VisitCompoundLiteralExpr(const CompoundLiteralExpr *E) {
return Success(E);
}
-bool LValueExprEvaluator::VisitMemberExpr(MemberExpr *E) {
+bool LValueExprEvaluator::VisitMemberExpr(const MemberExpr *E) {
QualType Ty;
if (E->isArrow()) {
if (!EvaluatePointer(E->getBase(), Result, Info))
@@ -444,10 +515,10 @@ bool LValueExprEvaluator::VisitMemberExpr(MemberExpr *E) {
Ty = E->getBase()->getType();
}
- RecordDecl *RD = Ty->getAs<RecordType>()->getDecl();
+ const RecordDecl *RD = Ty->getAs<RecordType>()->getDecl();
const ASTRecordLayout &RL = Info.Ctx.getASTRecordLayout(RD);
- FieldDecl *FD = dyn_cast<FieldDecl>(E->getMemberDecl());
+ const FieldDecl *FD = dyn_cast<FieldDecl>(E->getMemberDecl());
if (!FD) // FIXME: deal with other kinds of member expressions
return false;
@@ -467,7 +538,7 @@ bool LValueExprEvaluator::VisitMemberExpr(MemberExpr *E) {
return true;
}
-bool LValueExprEvaluator::VisitArraySubscriptExpr(ArraySubscriptExpr *E) {
+bool LValueExprEvaluator::VisitArraySubscriptExpr(const ArraySubscriptExpr *E) {
if (!EvaluatePointer(E->getBase(), Result, Info))
return false;
@@ -480,7 +551,7 @@ bool LValueExprEvaluator::VisitArraySubscriptExpr(ArraySubscriptExpr *E) {
return true;
}
-bool LValueExprEvaluator::VisitUnaryDeref(UnaryOperator *E) {
+bool LValueExprEvaluator::VisitUnaryDeref(const UnaryOperator *E) {
return EvaluatePointer(E->getSubExpr(), Result, Info);
}
@@ -490,11 +561,10 @@ bool LValueExprEvaluator::VisitUnaryDeref(UnaryOperator *E) {
namespace {
class PointerExprEvaluator
- : public StmtVisitor<PointerExprEvaluator, bool> {
- EvalInfo &Info;
+ : public ExprEvaluatorBase<PointerExprEvaluator, bool> {
LValue &Result;
- bool Success(Expr *E) {
+ bool Success(const Expr *E) {
Result.Base = E;
Result.Offset = CharUnits::Zero();
return true;
@@ -502,49 +572,41 @@ class PointerExprEvaluator
public:
PointerExprEvaluator(EvalInfo &info, LValue &Result)
- : Info(info), Result(Result) {}
+ : ExprEvaluatorBaseTy(info), Result(Result) {}
- bool VisitStmt(Stmt *S) {
- return false;
+ bool Success(const APValue &V, const Expr *E) {
+ Result.setFrom(V);
+ return true;
}
-
- bool VisitParenExpr(ParenExpr *E) { return Visit(E->getSubExpr()); }
- bool VisitGenericSelectionExpr(GenericSelectionExpr *E) {
- return Visit(E->getResultExpr());
+ bool Error(const Stmt *S) {
+ return false;
}
bool VisitBinaryOperator(const BinaryOperator *E);
- bool VisitCastExpr(CastExpr* E);
- bool VisitUnaryExtension(const UnaryOperator *E)
- { return Visit(E->getSubExpr()); }
+ bool VisitCastExpr(const CastExpr* E);
bool VisitUnaryAddrOf(const UnaryOperator *E);
- bool VisitObjCStringLiteral(ObjCStringLiteral *E)
+ bool VisitObjCStringLiteral(const ObjCStringLiteral *E)
{ return Success(E); }
- bool VisitAddrLabelExpr(AddrLabelExpr *E)
+ bool VisitAddrLabelExpr(const AddrLabelExpr *E)
{ return Success(E); }
- bool VisitCallExpr(CallExpr *E);
- bool VisitBlockExpr(BlockExpr *E) {
+ bool VisitCallExpr(const CallExpr *E);
+ bool VisitBlockExpr(const BlockExpr *E) {
if (!E->getBlockDecl()->hasCaptures())
return Success(E);
return false;
}
- bool VisitImplicitValueInitExpr(ImplicitValueInitExpr *E)
+ bool VisitImplicitValueInitExpr(const ImplicitValueInitExpr *E)
{ return Success((Expr*)0); }
- bool VisitBinaryConditionalOperator(BinaryConditionalOperator *E);
- bool VisitConditionalOperator(ConditionalOperator *E);
- bool VisitChooseExpr(ChooseExpr *E)
- { return Visit(E->getChosenSubExpr(Info.Ctx)); }
- bool VisitCXXNullPtrLiteralExpr(CXXNullPtrLiteralExpr *E)
+ bool VisitCXXNullPtrLiteralExpr(const CXXNullPtrLiteralExpr *E)
{ return Success((Expr*)0); }
- bool VisitOpaqueValueExpr(OpaqueValueExpr *E);
// FIXME: Missing: @protocol, @selector
};
} // end anonymous namespace
static bool EvaluatePointer(const Expr* E, LValue& Result, EvalInfo &Info) {
assert(E->getType()->hasPointerRepresentation());
- return PointerExprEvaluator(Info, Result).Visit(const_cast<Expr*>(E));
+ return PointerExprEvaluator(Info, Result).Visit(E);
}
bool PointerExprEvaluator::VisitBinaryOperator(const BinaryOperator *E) {
@@ -592,8 +654,8 @@ bool PointerExprEvaluator::VisitUnaryAddrOf(const UnaryOperator *E) {
}
-bool PointerExprEvaluator::VisitCastExpr(CastExpr* E) {
- Expr* SubExpr = E->getSubExpr();
+bool PointerExprEvaluator::VisitCastExpr(const CastExpr* E) {
+ const Expr* SubExpr = E->getSubExpr();
switch (E->getCastKind()) {
default:
@@ -671,42 +733,14 @@ bool PointerExprEvaluator::VisitCastExpr(CastExpr* E) {
return false;
}
-bool PointerExprEvaluator::VisitCallExpr(CallExpr *E) {
+bool PointerExprEvaluator::VisitCallExpr(const CallExpr *E) {
if (E->isBuiltinCall(Info.Ctx) ==
Builtin::BI__builtin___CFStringMakeConstantString ||
E->isBuiltinCall(Info.Ctx) ==
Builtin::BI__builtin___NSStringMakeConstantString)
return Success(E);
- return false;
-}
-
-bool PointerExprEvaluator::VisitOpaqueValueExpr(OpaqueValueExpr *e) {
- const APValue *value = Info.getOpaqueValue(e);
- if (!value)
- return (e->getSourceExpr() ? Visit(e->getSourceExpr()) : false);
- Result.setFrom(*value);
- return true;
-}
-
-bool PointerExprEvaluator::
-VisitBinaryConditionalOperator(BinaryConditionalOperator *e) {
- OpaqueValueEvaluation opaque(Info, e->getOpaqueValue(), e->getCommon());
- if (opaque.hasError()) return false;
- bool cond;
- if (!HandleConversionToBool(e->getCond(), cond, Info))
- return false;
-
- return Visit(cond ? e->getTrueExpr() : e->getFalseExpr());
-}
-
-bool PointerExprEvaluator::VisitConditionalOperator(ConditionalOperator *E) {
- bool BoolResult;
- if (!HandleConversionToBool(E->getCond(), BoolResult, Info))
- return false;
-
- Expr* EvalExpr = BoolResult ? E->getTrueExpr() : E->getFalseExpr();
- return Visit(EvalExpr);
+ return ExprEvaluatorBaseTy::VisitCallExpr(E);
}
//===----------------------------------------------------------------------===//
@@ -715,25 +749,15 @@ bool PointerExprEvaluator::VisitConditionalOperator(ConditionalOperator *E) {
namespace {
class VectorExprEvaluator
- : public StmtVisitor<VectorExprEvaluator, APValue> {
- EvalInfo &Info;
+ : public ExprEvaluatorBase<VectorExprEvaluator, APValue> {
APValue GetZeroVector(QualType VecType);
public:
- VectorExprEvaluator(EvalInfo &info) : Info(info) {}
+ VectorExprEvaluator(EvalInfo &info) : ExprEvaluatorBaseTy(info) {}
- APValue VisitStmt(Stmt *S) {
- return APValue();
- }
+ APValue Success(const APValue &V, const Expr *E) { return V; }
+ APValue Error(const Expr *E) { return APValue(); }
- APValue VisitParenExpr(ParenExpr *E)
- { return Visit(E->getSubExpr()); }
- APValue VisitGenericSelectionExpr(GenericSelectionExpr *E)
- { return Visit(E->getResultExpr()); }
- APValue VisitUnaryExtension(const UnaryOperator *E)
- { return Visit(E->getSubExpr()); }
- APValue VisitUnaryPlus(const UnaryOperator *E)
- { return Visit(E->getSubExpr()); }
APValue VisitUnaryReal(const UnaryOperator *E)
{ return Visit(E->getSubExpr()); }
APValue VisitImplicitValueInitExpr(const ImplicitValueInitExpr *E)
@@ -741,9 +765,6 @@ namespace {
APValue VisitCastExpr(const CastExpr* E);
APValue VisitCompoundLiteralExpr(const CompoundLiteralExpr *E);
APValue VisitInitListExpr(const InitListExpr *E);
- APValue VisitConditionalOperator(const ConditionalOperator *E);
- APValue VisitChooseExpr(const ChooseExpr *E)
- { return Visit(E->getChosenSubExpr(Info.Ctx)); }
APValue VisitUnaryImag(const UnaryOperator *E);
// FIXME: Missing: unary -, unary ~, binary add/sub/mul/div,
// binary comparisons, binary and/or/xor,
@@ -756,7 +777,7 @@ namespace {
static bool EvaluateVector(const Expr* E, APValue& Result, EvalInfo &Info) {
if (!E->getType()->isVectorType())
return false;
- Result = VectorExprEvaluator(Info).Visit(const_cast<Expr*>(E));
+ Result = VectorExprEvaluator(Info).Visit(E);
return !Result.isUninit();
}
@@ -792,7 +813,7 @@ APValue VectorExprEvaluator::VisitCastExpr(const CastExpr* E) {
}
case CK_BitCast: {
if (SETy->isVectorType())
- return Visit(const_cast<Expr*>(SE));
+ return Visit(SE);
if (!SETy->isIntegerType())
return APValue();
@@ -819,7 +840,7 @@ APValue VectorExprEvaluator::VisitCastExpr(const CastExpr* E) {
}
case CK_LValueToRValue:
case CK_NoOp:
- return Visit(const_cast<Expr*>(SE));
+ return Visit(SE);
default:
return APValue();
}
@@ -827,7 +848,7 @@ APValue VectorExprEvaluator::VisitCastExpr(const CastExpr* E) {
APValue
VectorExprEvaluator::VisitCompoundLiteralExpr(const CompoundLiteralExpr *E) {
- return this->Visit(const_cast<Expr*>(E->getInitializer()));
+ return this->Visit(E->getInitializer());
}
APValue
@@ -905,19 +926,6 @@ VectorExprEvaluator::GetZeroVector(QualType T) {
return APValue(&Elements[0], Elements.size());
}
-APValue VectorExprEvaluator::VisitConditionalOperator(const ConditionalOperator *E) {
- bool BoolResult;
- if (!HandleConversionToBool(E->getCond(), BoolResult, Info))
- return APValue();
-
- Expr* EvalExpr = BoolResult ? E->getTrueExpr() : E->getFalseExpr();
-
- APValue Result;
- if (EvaluateVector(EvalExpr, Result, Info))
- return Result;
- return APValue();
-}
-
APValue VectorExprEvaluator::VisitUnaryImag(const UnaryOperator *E) {
if (!E->getSubExpr()->isEvaluatable(Info.Ctx))
Info.EvalResult.HasSideEffects = true;
@@ -930,17 +938,16 @@ APValue VectorExprEvaluator::VisitUnaryImag(const UnaryOperator *E) {
namespace {
class IntExprEvaluator
- : public StmtVisitor<IntExprEvaluator, bool> {
- EvalInfo &Info;
+ : public ExprEvaluatorBase<IntExprEvaluator, bool> {
APValue &Result;
public:
IntExprEvaluator(EvalInfo &info, APValue &result)
- : Info(info), Result(result) {}
+ : ExprEvaluatorBaseTy(info), Result(result) {}
bool Success(const llvm::APSInt &SI, const Expr *E) {
assert(E->getType()->isIntegralOrEnumerationType() &&
"Invalid evaluation result.");
- assert(SI.isSigned() == E->getType()->isSignedIntegerType() &&
+ assert(SI.isSigned() == E->getType()->isSignedIntegerOrEnumerationType() &&
"Invalid evaluation result.");
assert(SI.getBitWidth() == Info.Ctx.getIntWidth(E->getType()) &&
"Invalid evaluation result.");
@@ -954,7 +961,8 @@ public:
assert(I.getBitWidth() == Info.Ctx.getIntWidth(E->getType()) &&
"Invalid evaluation result.");
Result = APValue(APSInt(I));
- Result.getInt().setIsUnsigned(E->getType()->isUnsignedIntegerType());
+ Result.getInt().setIsUnsigned(
+ E->getType()->isUnsignedIntegerOrEnumerationType());
return true;
}
@@ -980,23 +988,16 @@ public:
return false;
}
- //===--------------------------------------------------------------------===//
- // Visitor Methods
- //===--------------------------------------------------------------------===//
-
- bool VisitStmt(Stmt *) {
- assert(0 && "This should be called on integers, stmts are not integers");
- return false;
+ bool Success(const APValue &V, const Expr *E) {
+ return Success(V.getInt(), E);
}
-
- bool VisitExpr(Expr *E) {
+ bool Error(const Expr *E) {
return Error(E->getLocStart(), diag::note_invalid_subexpr_in_ice, E);
}
- bool VisitParenExpr(ParenExpr *E) { return Visit(E->getSubExpr()); }
- bool VisitGenericSelectionExpr(GenericSelectionExpr *E) {
- return Visit(E->getResultExpr());
- }
+ //===--------------------------------------------------------------------===//
+ // Visitor Methods
+ //===--------------------------------------------------------------------===//
bool VisitIntegerLiteral(const IntegerLiteral *E) {
return Success(E->getValue(), E);
@@ -1005,18 +1006,12 @@ public:
return Success(E->getValue(), E);
}
- bool VisitOpaqueValueExpr(OpaqueValueExpr *e) {
- const APValue *value = Info.getOpaqueValue(e);
- if (!value) {
- if (e->getSourceExpr()) return Visit(e->getSourceExpr());
- return Error(e->getExprLoc(), diag::note_invalid_subexpr_in_ice, e);
- }
- return Success(value->getInt(), e);
- }
-
bool CheckReferencedDecl(const Expr *E, const Decl *D);
bool VisitDeclRefExpr(const DeclRefExpr *E) {
- return CheckReferencedDecl(E, E->getDecl());
+ if (CheckReferencedDecl(E, E->getDecl()))
+ return true;
+
+ return ExprEvaluatorBaseTy::VisitDeclRefExpr(E);
}
bool VisitMemberExpr(const MemberExpr *E) {
if (CheckReferencedDecl(E, E->getMemberDecl())) {
@@ -1024,17 +1019,16 @@ public:
Info.EvalResult.HasSideEffects = true;
return true;
}
- return false;
+
+ return ExprEvaluatorBaseTy::VisitMemberExpr(E);
}
- bool VisitCallExpr(CallExpr *E);
+ bool VisitCallExpr(const CallExpr *E);
bool VisitBinaryOperator(const BinaryOperator *E);
bool VisitOffsetOfExpr(const OffsetOfExpr *E);
bool VisitUnaryOperator(const UnaryOperator *E);
- bool VisitConditionalOperator(const ConditionalOperator *E);
- bool VisitBinaryConditionalOperator(const BinaryConditionalOperator *E);
- bool VisitCastExpr(CastExpr* E);
+ bool VisitCastExpr(const CastExpr* E);
bool VisitUnaryExprOrTypeTraitExpr(const UnaryExprOrTypeTraitExpr *E);
bool VisitCXXBoolLiteralExpr(const CXXBoolLiteralExpr *E) {
@@ -1069,10 +1063,6 @@ public:
return Success(E->getValue(), E);
}
- bool VisitChooseExpr(const ChooseExpr *E) {
- return Visit(E->getChosenSubExpr(Info.Ctx));
- }
-
bool VisitUnaryReal(const UnaryOperator *E);
bool VisitUnaryImag(const UnaryOperator *E);
@@ -1083,14 +1073,14 @@ private:
CharUnits GetAlignOfExpr(const Expr *E);
CharUnits GetAlignOfType(QualType T);
static QualType GetObjectType(const Expr *E);
- bool TryEvaluateBuiltinObjectSize(CallExpr *E);
+ bool TryEvaluateBuiltinObjectSize(const CallExpr *E);
// FIXME: Missing: array subscript of vector, member of vector
};
} // end anonymous namespace
static bool EvaluateIntegerOrLValue(const Expr* E, APValue &Result, EvalInfo &Info) {
assert(E->getType()->isIntegralOrEnumerationType());
- return IntExprEvaluator(Info, Result).Visit(const_cast<Expr*>(E));
+ return IntExprEvaluator(Info, Result).Visit(E);
}
static bool EvaluateInteger(const Expr* E, APSInt &Result, EvalInfo &Info) {
@@ -1114,18 +1104,18 @@ bool IntExprEvaluator::CheckReferencedDecl(const Expr* E, const Decl* D) {
== Qualifiers::Const) {
if (isa<ParmVarDecl>(D))
- return Error(E->getLocStart(), diag::note_invalid_subexpr_in_ice, E);
+ return false;
if (const VarDecl *VD = dyn_cast<VarDecl>(D)) {
if (const Expr *Init = VD->getAnyInitializer()) {
if (APValue *V = VD->getEvaluatedValue()) {
if (V->isInt())
return Success(V->getInt(), E);
- return Error(E->getLocStart(), diag::note_invalid_subexpr_in_ice, E);
+ return false;
}
if (VD->isEvaluatingValue())
- return Error(E->getLocStart(), diag::note_invalid_subexpr_in_ice, E);
+ return false;
VD->setEvaluatingValue();
@@ -1144,7 +1134,7 @@ bool IntExprEvaluator::CheckReferencedDecl(const Expr* E, const Decl* D) {
}
// Otherwise, random variable references are not constants.
- return Error(E->getLocStart(), diag::note_invalid_subexpr_in_ice, E);
+ return false;
}
/// EvaluateBuiltinClassifyType - Evaluate __builtin_classify_type the same way
@@ -1216,7 +1206,7 @@ QualType IntExprEvaluator::GetObjectType(const Expr *E) {
return QualType();
}
-bool IntExprEvaluator::TryEvaluateBuiltinObjectSize(CallExpr *E) {
+bool IntExprEvaluator::TryEvaluateBuiltinObjectSize(const CallExpr *E) {
// TODO: Perhaps we should let LLVM lower this?
LValue Base;
if (!EvaluatePointer(E->getArg(0), Base, Info))
@@ -1244,10 +1234,10 @@ bool IntExprEvaluator::TryEvaluateBuiltinObjectSize(CallExpr *E) {
return Success(Size, E);
}
-bool IntExprEvaluator::VisitCallExpr(CallExpr *E) {
+bool IntExprEvaluator::VisitCallExpr(const CallExpr *E) {
switch (E->isBuiltinCall(Info.Ctx)) {
default:
- return Error(E->getLocStart(), diag::note_invalid_subexpr_in_ice, E);
+ return ExprEvaluatorBaseTy::VisitCallExpr(E);
case Builtin::BI__builtin_object_size: {
if (TryEvaluateBuiltinObjectSize(E))
@@ -1285,7 +1275,7 @@ bool IntExprEvaluator::VisitCallExpr(CallExpr *E) {
case Builtin::BI__builtin_strlen:
// As an extension, we support strlen() and __builtin_strlen() as constant
// expressions when the argument is a string literal.
- if (StringLiteral *S
+ if (const StringLiteral *S
= dyn_cast<StringLiteral>(E->getArg(0)->IgnoreParenImpCasts())) {
// The string literal may have embedded null characters. Find the first
// one and truncate there.
@@ -1574,26 +1564,6 @@ bool IntExprEvaluator::VisitBinaryOperator(const BinaryOperator *E) {
}
}
-bool IntExprEvaluator::
-VisitBinaryConditionalOperator(const BinaryConditionalOperator *e) {
- OpaqueValueEvaluation opaque(Info, e->getOpaqueValue(), e->getCommon());
- if (opaque.hasError()) return false;
-
- bool cond;
- if (!HandleConversionToBool(e->getCond(), cond, Info))
- return false;
-
- return Visit(cond ? e->getTrueExpr() : e->getFalseExpr());
-}
-
-bool IntExprEvaluator::VisitConditionalOperator(const ConditionalOperator *E) {
- bool Cond;
- if (!HandleConversionToBool(E->getCond(), Cond, Info))
- return false;
-
- return Visit(Cond ? E->getTrueExpr() : E->getFalseExpr());
-}
-
CharUnits IntExprEvaluator::GetAlignOfType(QualType T) {
// C++ [expr.sizeof]p2: "When applied to a reference or a reference type,
// the result is the size of the referenced type."
@@ -1679,18 +1649,17 @@ bool IntExprEvaluator::VisitUnaryExprOrTypeTraitExpr(
return false;
}
-bool IntExprEvaluator::VisitOffsetOfExpr(const OffsetOfExpr *E) {
+bool IntExprEvaluator::VisitOffsetOfExpr(const OffsetOfExpr *OOE) {
CharUnits Result;
- unsigned n = E->getNumComponents();
- OffsetOfExpr* OOE = const_cast<OffsetOfExpr*>(E);
+ unsigned n = OOE->getNumComponents();
if (n == 0)
return false;
- QualType CurrentType = E->getTypeSourceInfo()->getType();
+ QualType CurrentType = OOE->getTypeSourceInfo()->getType();
for (unsigned i = 0; i != n; ++i) {
OffsetOfExpr::OffsetOfNode ON = OOE->getComponent(i);
switch (ON.getKind()) {
case OffsetOfExpr::OffsetOfNode::Array: {
- Expr *Idx = OOE->getIndexExpr(ON.getArrayExprIndex());
+ const Expr *Idx = OOE->getIndexExpr(ON.getArrayExprIndex());
APSInt IdxResult;
if (!EvaluateInteger(Idx, IdxResult, Info))
return false;
@@ -1745,7 +1714,7 @@ bool IntExprEvaluator::VisitOffsetOfExpr(const OffsetOfExpr *E) {
}
}
}
- return Success(Result, E);
+ return Success(Result, OOE);
}
bool IntExprEvaluator::VisitUnaryOperator(const UnaryOperator *E) {
@@ -1788,8 +1757,8 @@ bool IntExprEvaluator::VisitUnaryOperator(const UnaryOperator *E) {
/// HandleCast - This is used to evaluate implicit or explicit casts where the
/// result type is integer.
-bool IntExprEvaluator::VisitCastExpr(CastExpr *E) {
- Expr *SubExpr = E->getSubExpr();
+bool IntExprEvaluator::VisitCastExpr(const CastExpr *E) {
+ const Expr *SubExpr = E->getSubExpr();
QualType DestType = E->getType();
QualType SrcType = SubExpr->getType();
@@ -1936,48 +1905,33 @@ bool IntExprEvaluator::VisitCXXNoexceptExpr(const CXXNoexceptExpr *E) {
namespace {
class FloatExprEvaluator
- : public StmtVisitor<FloatExprEvaluator, bool> {
- EvalInfo &Info;
+ : public ExprEvaluatorBase<FloatExprEvaluator, bool> {
APFloat &Result;
public:
FloatExprEvaluator(EvalInfo &info, APFloat &result)
- : Info(info), Result(result) {}
+ : ExprEvaluatorBaseTy(info), Result(result) {}
- bool VisitStmt(Stmt *S) {
+ bool Success(const APValue &V, const Expr *e) {
+ Result = V.getFloat();
+ return true;
+ }
+ bool Error(const Stmt *S) {
return false;
}
- bool VisitParenExpr(ParenExpr *E) { return Visit(E->getSubExpr()); }
- bool VisitGenericSelectionExpr(GenericSelectionExpr *E) {
- return Visit(E->getResultExpr());
- }
bool VisitCallExpr(const CallExpr *E);
bool VisitUnaryOperator(const UnaryOperator *E);
bool VisitBinaryOperator(const BinaryOperator *E);
bool VisitFloatingLiteral(const FloatingLiteral *E);
- bool VisitCastExpr(CastExpr *E);
- bool VisitCXXScalarValueInitExpr(CXXScalarValueInitExpr *E);
- bool VisitConditionalOperator(ConditionalOperator *E);
- bool VisitBinaryConditionalOperator(BinaryConditionalOperator *E);
+ bool VisitCastExpr(const CastExpr *E);
+ bool VisitCXXScalarValueInitExpr(const CXXScalarValueInitExpr *E);
- bool VisitChooseExpr(const ChooseExpr *E)
- { 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);
bool VisitDeclRefExpr(const DeclRefExpr *E);
- bool VisitOpaqueValueExpr(const OpaqueValueExpr *e) {
- const APValue *value = Info.getOpaqueValue(e);
- if (!value)
- return (e->getSourceExpr() ? Visit(e->getSourceExpr()) : false);
- Result = value->getFloat();
- return true;
- }
-
// FIXME: Missing: array subscript of vector, member of vector,
// ImplicitValueInitExpr
};
@@ -1985,7 +1939,7 @@ public:
static bool EvaluateFloat(const Expr* E, APFloat& Result, EvalInfo &Info) {
assert(E->getType()->isRealFloatingType());
- return FloatExprEvaluator(Info, Result).Visit(const_cast<Expr*>(E));
+ return FloatExprEvaluator(Info, Result).Visit(E);
}
static bool TryEvaluateBuiltinNaN(const ASTContext &Context,
@@ -2015,7 +1969,9 @@ static bool TryEvaluateBuiltinNaN(const ASTContext &Context,
bool FloatExprEvaluator::VisitCallExpr(const CallExpr *E) {
switch (E->isBuiltinCall(Info.Ctx)) {
- default: return false;
+ default:
+ return ExprEvaluatorBaseTy::VisitCallExpr(E);
+
case Builtin::BI__builtin_huge_val:
case Builtin::BI__builtin_huge_valf:
case Builtin::BI__builtin_huge_vall:
@@ -2066,6 +2022,9 @@ bool FloatExprEvaluator::VisitCallExpr(const CallExpr *E) {
}
bool FloatExprEvaluator::VisitDeclRefExpr(const DeclRefExpr *E) {
+ if (ExprEvaluatorBaseTy::VisitDeclRefExpr(E))
+ return true;
+
const Decl *D = E->getDecl();
if (!isa<VarDecl>(D) || isa<ParmVarDecl>(D)) return false;
const VarDecl *VD = cast<VarDecl>(D);
@@ -2196,8 +2155,8 @@ bool FloatExprEvaluator::VisitFloatingLiteral(const FloatingLiteral *E) {
return true;
}
-bool FloatExprEvaluator::VisitCastExpr(CastExpr *E) {
- Expr* SubExpr = E->getSubExpr();
+bool FloatExprEvaluator::VisitCastExpr(const CastExpr *E) {
+ const Expr* SubExpr = E->getSubExpr();
switch (E->getCastKind()) {
default:
@@ -2236,77 +2195,42 @@ bool FloatExprEvaluator::VisitCastExpr(CastExpr *E) {
return false;
}
-bool FloatExprEvaluator::VisitCXXScalarValueInitExpr(CXXScalarValueInitExpr *E) {
+bool FloatExprEvaluator::VisitCXXScalarValueInitExpr(const CXXScalarValueInitExpr *E) {
Result = APFloat::getZero(Info.Ctx.getFloatTypeSemantics(E->getType()));
return true;
}
-bool FloatExprEvaluator::
-VisitBinaryConditionalOperator(BinaryConditionalOperator *e) {
- OpaqueValueEvaluation opaque(Info, e->getOpaqueValue(), e->getCommon());
- if (opaque.hasError()) return false;
-
- bool cond;
- if (!HandleConversionToBool(e->getCond(), cond, Info))
- return false;
-
- return Visit(cond ? e->getTrueExpr() : e->getFalseExpr());
-}
-
-bool FloatExprEvaluator::VisitConditionalOperator(ConditionalOperator *E) {
- bool Cond;
- if (!HandleConversionToBool(E->getCond(), Cond, Info))
- return false;
-
- return Visit(Cond ? E->getTrueExpr() : E->getFalseExpr());
-}
-
//===----------------------------------------------------------------------===//
// Complex Evaluation (for float and integer)
//===----------------------------------------------------------------------===//
namespace {
class ComplexExprEvaluator
- : public StmtVisitor<ComplexExprEvaluator, bool> {
- EvalInfo &Info;
+ : public ExprEvaluatorBase<ComplexExprEvaluator, bool> {
ComplexValue &Result;
public:
ComplexExprEvaluator(EvalInfo &info, ComplexValue &Result)
- : Info(info), Result(Result) {}
+ : ExprEvaluatorBaseTy(info), Result(Result) {}
- //===--------------------------------------------------------------------===//
- // Visitor Methods
- //===--------------------------------------------------------------------===//
-
- bool VisitStmt(Stmt *S) {
+ bool Success(const APValue &V, const Expr *e) {
+ Result.setFrom(V);
+ return true;
+ }
+ bool Error(const Expr *E) {
return false;
}
- bool VisitParenExpr(ParenExpr *E) { return Visit(E->getSubExpr()); }
- bool VisitGenericSelectionExpr(GenericSelectionExpr *E) {
- return Visit(E->getResultExpr());
- }
+ //===--------------------------------------------------------------------===//
+ // Visitor Methods
+ //===--------------------------------------------------------------------===//
- bool VisitImaginaryLiteral(ImaginaryLiteral *E);
+ bool VisitImaginaryLiteral(const ImaginaryLiteral *E);
- bool VisitCastExpr(CastExpr *E);
+ bool VisitCastExpr(const CastExpr *E);
bool VisitBinaryOperator(const BinaryOperator *E);
bool VisitUnaryOperator(const UnaryOperator *E);
- bool VisitConditionalOperator(const ConditionalOperator *E);
- bool VisitBinaryConditionalOperator(const BinaryConditionalOperator *E);
- bool VisitChooseExpr(const ChooseExpr *E)
- { return Visit(E->getChosenSubExpr(Info.Ctx)); }
- bool VisitUnaryExtension(const UnaryOperator *E)
- { return Visit(E->getSubExpr()); }
- bool VisitOpaqueValueExpr(const OpaqueValueExpr *e) {
- const APValue *value = Info.getOpaqueValue(e);
- if (!value)
- return (e->getSourceExpr() ? Visit(e->getSourceExpr()) : false);
- Result.setFrom(*value);
- return true;
- }
// FIXME Missing: ImplicitValueInitExpr
};
} // end anonymous namespace
@@ -2314,11 +2238,11 @@ public:
static bool EvaluateComplex(const Expr *E, ComplexValue &Result,
EvalInfo &Info) {
assert(E->getType()->isAnyComplexType());
- return ComplexExprEvaluator(Info, Result).Visit(const_cast<Expr*>(E));
+ return ComplexExprEvaluator(Info, Result).Visit(E);
}
-bool ComplexExprEvaluator::VisitImaginaryLiteral(ImaginaryLiteral *E) {
- Expr* SubExpr = E->getSubExpr();
+bool ComplexExprEvaluator::VisitImaginaryLiteral(const ImaginaryLiteral *E) {
+ const Expr* SubExpr = E->getSubExpr();
if (SubExpr->getType()->isRealFloatingType()) {
Result.makeComplexFloat();
@@ -2342,7 +2266,7 @@ bool ComplexExprEvaluator::VisitImaginaryLiteral(ImaginaryLiteral *E) {
}
}
-bool ComplexExprEvaluator::VisitCastExpr(CastExpr *E) {
+bool ComplexExprEvaluator::VisitCastExpr(const CastExpr *E) {
switch (E->getCastKind()) {
case CK_BitCast:
@@ -2627,26 +2551,6 @@ bool ComplexExprEvaluator::VisitUnaryOperator(const UnaryOperator *E) {
}
}
-bool ComplexExprEvaluator::
-VisitBinaryConditionalOperator(const BinaryConditionalOperator *e) {
- OpaqueValueEvaluation opaque(Info, e->getOpaqueValue(), e->getCommon());
- if (opaque.hasError()) return false;
-
- bool cond;
- if (!HandleConversionToBool(e->getCond(), cond, Info))
- return false;
-
- return Visit(cond ? e->getTrueExpr() : e->getFalseExpr());
-}
-
-bool ComplexExprEvaluator::VisitConditionalOperator(const ConditionalOperator *E) {
- bool Cond;
- if (!HandleConversionToBool(E->getCond(), Cond, Info))
- return false;
-
- return Visit(Cond ? E->getTrueExpr() : E->getFalseExpr());
-}
-
//===----------------------------------------------------------------------===//
// Top level Expr::Evaluate method.
//===----------------------------------------------------------------------===//
@@ -2655,8 +2559,8 @@ static bool Evaluate(EvalInfo &Info, const Expr *E) {
if (E->getType()->isVectorType()) {
if (!EvaluateVector(E, Info.EvalResult.Val, Info))
return false;
- } else if (E->getType()->isIntegerType()) {
- if (!IntExprEvaluator(Info, Info.EvalResult.Val).Visit(const_cast<Expr*>(E)))
+ } else if (E->getType()->isIntegralOrEnumerationType()) {
+ if (!IntExprEvaluator(Info, Info.EvalResult.Val).Visit(E))
return false;
if (Info.EvalResult.Val.isLValue() &&
!IsGlobalLValue(Info.EvalResult.Val.getLValueBase()))
@@ -2737,7 +2641,7 @@ bool Expr::isEvaluatable(const ASTContext &Ctx) const {
bool Expr::HasSideEffects(const ASTContext &Ctx) const {
Expr::EvalResult Result;
EvalInfo Info(Ctx, Result);
- return HasSideEffect(Info).Visit(const_cast<Expr*>(this));
+ return HasSideEffect(Info).Visit(this);
}
APSInt Expr::EvaluateAsInt(const ASTContext &Ctx) const {
@@ -2866,6 +2770,7 @@ static ICEDiag CheckICE(const Expr* E, ASTContext &Ctx) {
case Expr::OpaqueValueExprClass:
case Expr::PackExpansionExprClass:
case Expr::SubstNonTypeTemplateParmPackExprClass:
+ case Expr::AsTypeExprClass:
return ICEDiag(2, E->getLocStart());
case Expr::SizeOfPackExprClass:
@@ -3053,6 +2958,21 @@ static ICEDiag CheckICE(const Expr* E, ASTContext &Ctx) {
case BO_LAnd:
case BO_LOr: {
ICEDiag LHSResult = CheckICE(Exp->getLHS(), Ctx);
+
+ // C++0x [expr.const]p2:
+ // [...] subexpressions of logical AND (5.14), logical OR
+ // (5.15), and condi- tional (5.16) operations that are not
+ // evaluated are not considered.
+ if (Ctx.getLangOptions().CPlusPlus0x && LHSResult.Val == 0) {
+ if (Exp->getOpcode() == BO_LAnd &&
+ Exp->getLHS()->EvaluateAsInt(Ctx) == 0)
+ return LHSResult;
+
+ if (Exp->getOpcode() == BO_LOr &&
+ Exp->getLHS()->EvaluateAsInt(Ctx) != 0)
+ return LHSResult;
+ }
+
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
@@ -3111,10 +3031,22 @@ static ICEDiag CheckICE(const Expr* E, ASTContext &Ctx) {
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;
+
+ // C++0x [expr.const]p2:
+ // subexpressions of [...] conditional (5.16) operations that
+ // are not evaluated are not considered
+ bool TrueBranch = Ctx.getLangOptions().CPlusPlus0x
+ ? Exp->getCond()->EvaluateAsInt(Ctx) != 0
+ : false;
+ ICEDiag TrueResult = NoDiag();
+ if (!Ctx.getLangOptions().CPlusPlus0x || TrueBranch)
+ TrueResult = CheckICE(Exp->getTrueExpr(), Ctx);
+ ICEDiag FalseResult = NoDiag();
+ if (!Ctx.getLangOptions().CPlusPlus0x || !TrueBranch)
+ FalseResult = CheckICE(Exp->getFalseExpr(), Ctx);
+
if (TrueResult.Val == 2)
return TrueResult;
if (FalseResult.Val == 2)
diff --git a/lib/AST/ExternalASTSource.cpp b/lib/AST/ExternalASTSource.cpp
index 89bf56d..f428318 100644
--- a/lib/AST/ExternalASTSource.cpp
+++ b/lib/AST/ExternalASTSource.cpp
@@ -57,3 +57,5 @@ ExternalASTSource::FindExternalLexicalDecls(const DeclContext *DC,
llvm::SmallVectorImpl<Decl*> &Result) {
return true;
}
+
+void ExternalASTSource::getMemoryBufferSizes(MemoryBufferSizes &sizes) const { }
diff --git a/lib/AST/ItaniumMangle.cpp b/lib/AST/ItaniumMangle.cpp
index c460929..e81ec7e 100644
--- a/lib/AST/ItaniumMangle.cpp
+++ b/lib/AST/ItaniumMangle.cpp
@@ -255,7 +255,8 @@ private:
DeclarationName name,
unsigned KnownArity = UnknownArity);
- void mangleUnresolvedType(QualType type);
+ static bool isUnresolvedType(const Type *type);
+ void mangleUnresolvedType(const Type *type);
void mangleName(const TemplateDecl *TD,
const TemplateArgument *TemplateArgs,
@@ -277,6 +278,7 @@ private:
unsigned NumTemplateArgs);
void manglePrefix(NestedNameSpecifier *qualifier);
void manglePrefix(const DeclContext *DC, bool NoFunction=false);
+ void manglePrefix(QualType type);
void mangleTemplatePrefix(const TemplateDecl *ND);
void mangleTemplatePrefix(TemplateName Template);
void mangleOperatorName(OverloadedOperatorKind OO, unsigned Arity);
@@ -317,6 +319,8 @@ private:
void mangleTemplateArgs(const TemplateParameterList &PL,
const TemplateArgumentList &AL);
void mangleTemplateArg(const NamedDecl *P, const TemplateArgument &A);
+ void mangleUnresolvedTemplateArgs(const TemplateArgument *args,
+ unsigned numArgs);
void mangleTemplateParameter(unsigned Index);
@@ -667,7 +671,7 @@ void CXXNameMangler::mangleCallOffset(int64_t NonVirtual, int64_t Virtual) {
Out << '_';
}
-void CXXNameMangler::mangleUnresolvedType(QualType type) {
+void CXXNameMangler::manglePrefix(QualType type) {
if (const TemplateSpecializationType *TST =
type->getAs<TemplateSpecializationType>()) {
if (!mangleSubstitution(QualType(TST, 0))) {
@@ -698,6 +702,31 @@ void CXXNameMangler::mangleUnresolvedType(QualType type) {
}
}
+/// Returns true if the given type, appearing within an
+/// unresolved-name, should be mangled as an unresolved-type.
+bool CXXNameMangler::isUnresolvedType(const Type *type) {
+ // <unresolved-type> ::= <template-param>
+ // ::= <decltype>
+ // ::= <template-template-param> <template-args>
+ // (this last is not official yet)
+
+ if (isa<TemplateTypeParmType>(type)) return true;
+ if (isa<DecltypeType>(type)) return true;
+ // typeof?
+ if (const TemplateSpecializationType *tst =
+ dyn_cast<TemplateSpecializationType>(type)) {
+ TemplateDecl *temp = tst->getTemplateName().getAsTemplateDecl();
+ if (temp && isa<TemplateTemplateParmDecl>(temp))
+ return true;
+ }
+ return false;
+}
+
+void CXXNameMangler::mangleUnresolvedType(const Type *type) {
+ // This seems to be do everything we want.
+ mangleType(QualType(type, 0));
+}
+
/// Mangle everything prior to the base-unresolved-name in an unresolved-name.
///
/// \param firstQualifierLookup - the entity found by unqualified lookup
@@ -752,17 +781,60 @@ void CXXNameMangler::mangleUnresolvedPrefix(NestedNameSpecifier *qualifier,
case NestedNameSpecifier::TypeSpec:
case NestedNameSpecifier::TypeSpecWithTemplate: {
- // Both cases want this.
- Out << "sr";
+ const Type *type = qualifier->getAsType();
- // We only get here recursively if we're followed by identifiers.
- if (recursive) Out << 'N';
+ // We only want to use an unresolved-type encoding if this is one of:
+ // - a decltype
+ // - a template type parameter
+ // - a template template parameter with arguments
+ // In all of these cases, we should have no prefix.
+ if (qualifier->getPrefix()) {
+ mangleUnresolvedPrefix(qualifier->getPrefix(), firstQualifierLookup,
+ /*recursive*/ true);
+ } else {
+ // Otherwise, all the cases want this.
+ Out << "sr";
- mangleUnresolvedType(QualType(qualifier->getAsType(), 0));
+ if (isUnresolvedType(type)) {
+ // We only get here recursively if we're followed by identifiers.
+ if (recursive) Out << 'N';
+ mangleUnresolvedType(type);
- // We never want to print 'E' directly after an unresolved-type,
- // so we return directly.
- return;
+ // We never want to print 'E' directly after an unresolved-type,
+ // so we return directly.
+ return;
+ }
+ }
+
+ assert(!isUnresolvedType(type));
+
+ // Only certain other types are valid as prefixes; enumerate them.
+ // FIXME: can we get ElaboratedTypes here?
+ // FIXME: SubstTemplateTypeParmType?
+ if (const TagType *t = dyn_cast<TagType>(type)) {
+ mangleSourceName(t->getDecl()->getIdentifier());
+ } else if (const TypedefType *t = dyn_cast<TypedefType>(type)) {
+ mangleSourceName(t->getDecl()->getIdentifier());
+ } else if (const UnresolvedUsingType *t
+ = dyn_cast<UnresolvedUsingType>(type)) {
+ mangleSourceName(t->getDecl()->getIdentifier());
+ } else if (const DependentNameType *t
+ = dyn_cast<DependentNameType>(type)) {
+ mangleSourceName(t->getIdentifier());
+ } else if (const TemplateSpecializationType *tst
+ = dyn_cast<TemplateSpecializationType>(type)) {
+ TemplateDecl *temp = tst->getTemplateName().getAsTemplateDecl();
+ assert(temp && "no template for template specialization type");
+ mangleSourceName(temp->getIdentifier());
+ mangleUnresolvedTemplateArgs(tst->getArgs(), tst->getNumArgs());
+ } else if (const DependentTemplateSpecializationType *tst
+ = dyn_cast<DependentTemplateSpecializationType>(type)) {
+ mangleSourceName(tst->getIdentifier());
+ mangleUnresolvedTemplateArgs(tst->getArgs(), tst->getNumArgs());
+ } else {
+ llvm_unreachable("unexpected type in nested name specifier!");
+ }
+ break;
}
case NestedNameSpecifier::Identifier:
@@ -1050,6 +1122,12 @@ void CXXNameMangler::mangleLocalName(const NamedDecl *ND) {
// := Z <function encoding> E s [<discriminator>]
// <discriminator> := _ <non-negative number>
const DeclContext *DC = ND->getDeclContext();
+ if (isa<ObjCMethodDecl>(DC) && isa<FunctionDecl>(ND)) {
+ // Don't add objc method name mangling to locally declared function
+ mangleUnqualifiedName(ND);
+ return;
+ }
+
Out << 'Z';
if (const ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(DC)) {
@@ -1097,7 +1175,7 @@ void CXXNameMangler::manglePrefix(NestedNameSpecifier *qualifier) {
case NestedNameSpecifier::TypeSpec:
case NestedNameSpecifier::TypeSpecWithTemplate:
- mangleUnresolvedType(QualType(qualifier->getAsType(), 0));
+ manglePrefix(QualType(qualifier->getAsType(), 0));
return;
case NestedNameSpecifier::Identifier:
@@ -1867,6 +1945,22 @@ void CXXNameMangler::mangleType(const DecltypeType *T) {
Out << 'E';
}
+void CXXNameMangler::mangleType(const UnaryTransformType *T) {
+ // If this is dependent, we need to record that. If not, we simply
+ // mangle it as the underlying type since they are equivalent.
+ if (T->isDependentType()) {
+ Out << 'U';
+
+ switch (T->getUTTKind()) {
+ case UnaryTransformType::EnumUnderlyingType:
+ Out << "3eut";
+ break;
+ }
+ }
+
+ mangleType(T->getUnderlyingType());
+}
+
void CXXNameMangler::mangleType(const AutoType *T) {
QualType D = T->getDeducedType();
// <builtin-type> ::= Da # dependent auto
@@ -1951,6 +2045,7 @@ void CXXNameMangler::mangleExpression(const Expr *E, unsigned Arity) {
// ::= <function-param>
// ::= sr <type> <unqualified-name> # dependent name
// ::= sr <type> <unqualified-name> <template-args> # dependent template-id
+ // ::= ds <expression> <expression> # expr.*expr
// ::= sZ <template-param> # size of a parameter pack
// ::= sZ <function-param> # size of a function parameter pack
// ::= <expr-primary>
@@ -2005,7 +2100,9 @@ void CXXNameMangler::mangleExpression(const Expr *E, unsigned Arity) {
case Expr::VAArgExprClass:
case Expr::CXXUuidofExprClass:
case Expr::CXXNoexceptExprClass:
- case Expr::CUDAKernelCallExprClass: {
+ case Expr::CUDAKernelCallExprClass:
+ case Expr::AsTypeExprClass:
+ {
// As bad as this diagnostic is, it's better than crashing.
Diagnostic &Diags = Context.getDiags();
unsigned DiagID = Diags.getCustomDiagID(Diagnostic::Error,
@@ -2227,8 +2324,11 @@ void CXXNameMangler::mangleExpression(const Expr *E, unsigned Arity) {
case Expr::CompoundAssignOperatorClass: // fallthrough
case Expr::BinaryOperatorClass: {
const BinaryOperator *BO = cast<BinaryOperator>(E);
- mangleOperatorName(BinaryOperator::getOverloadedOperator(BO->getOpcode()),
- /*Arity=*/2);
+ if (BO->getOpcode() == BO_PtrMemD)
+ Out << "ds";
+ else
+ mangleOperatorName(BinaryOperator::getOverloadedOperator(BO->getOpcode()),
+ /*Arity=*/2);
mangleExpression(BO->getLHS());
mangleExpression(BO->getRHS());
break;
@@ -2552,8 +2652,8 @@ void CXXNameMangler::mangleTemplateArgs(
const ExplicitTemplateArgumentList &TemplateArgs) {
// <template-args> ::= I <template-arg>+ E
Out << 'I';
- for (unsigned I = 0, E = TemplateArgs.NumTemplateArgs; I != E; ++I)
- mangleTemplateArg(0, TemplateArgs.getTemplateArgs()[I].getArgument());
+ for (unsigned i = 0, e = TemplateArgs.NumTemplateArgs; i != e; ++i)
+ mangleTemplateArg(0, TemplateArgs.getTemplateArgs()[i].getArgument());
Out << 'E';
}
@@ -2564,10 +2664,15 @@ void CXXNameMangler::mangleTemplateArgs(TemplateName Template,
return mangleTemplateArgs(*TD->getTemplateParameters(), TemplateArgs,
NumTemplateArgs);
+ mangleUnresolvedTemplateArgs(TemplateArgs, NumTemplateArgs);
+}
+
+void CXXNameMangler::mangleUnresolvedTemplateArgs(const TemplateArgument *args,
+ unsigned numArgs) {
// <template-args> ::= I <template-arg>+ E
Out << 'I';
- for (unsigned i = 0; i != NumTemplateArgs; ++i)
- mangleTemplateArg(0, TemplateArgs[i]);
+ for (unsigned i = 0; i != numArgs; ++i)
+ mangleTemplateArg(0, args[i]);
Out << 'E';
}
diff --git a/lib/AST/Mangle.cpp b/lib/AST/Mangle.cpp
index 3a0b909..c3f3b11 100644
--- a/lib/AST/Mangle.cpp
+++ b/lib/AST/Mangle.cpp
@@ -48,6 +48,11 @@ static void checkMangleDC(const DeclContext *DC, const BlockDecl *BD) {
const DeclContext *ExpectedDC = BD->getDeclContext();
while (isa<BlockDecl>(ExpectedDC) || isa<EnumDecl>(ExpectedDC))
ExpectedDC = ExpectedDC->getParent();
+ // In-class initializers for non-static data members are lexically defined
+ // within the class, but are mangled as if they were specified as constructor
+ // member initializers.
+ if (isa<CXXRecordDecl>(ExpectedDC) && DC != ExpectedDC)
+ DC = DC->getParent();
assert(DC == ExpectedDC && "Given decl context did not match expected!");
#endif
}
diff --git a/lib/AST/MicrosoftMangle.cpp b/lib/AST/MicrosoftMangle.cpp
index 5424beb..4f920f9 100644
--- a/lib/AST/MicrosoftMangle.cpp
+++ b/lib/AST/MicrosoftMangle.cpp
@@ -1113,6 +1113,10 @@ void MicrosoftCXXNameMangler::mangleType(const DecltypeType *T) {
assert(false && "Don't know how to mangle DecltypeTypes yet!");
}
+void MicrosoftCXXNameMangler::mangleType(const UnaryTransformType *T) {
+ assert(false && "Don't know how to mangle UnaryTransformationTypes yet!");
+}
+
void MicrosoftCXXNameMangler::mangleType(const AutoType *T) {
assert(false && "Don't know how to mangle AutoTypes yet!");
}
diff --git a/lib/AST/RecordLayoutBuilder.cpp b/lib/AST/RecordLayoutBuilder.cpp
index 0770e1f..de0b1d0 100644
--- a/lib/AST/RecordLayoutBuilder.cpp
+++ b/lib/AST/RecordLayoutBuilder.cpp
@@ -582,7 +582,7 @@ protected:
CharUnits NonVirtualSize;
CharUnits NonVirtualAlignment;
- CharUnits ZeroLengthBitfieldAlignment;
+ FieldDecl *ZeroLengthBitfield;
/// PrimaryBase - the primary base class (if one exists) of the class
/// we're laying out.
@@ -621,7 +621,7 @@ protected:
UnfilledBitsInLastByte(0), MaxFieldAlignment(CharUnits::Zero()),
DataSize(0), NonVirtualSize(CharUnits::Zero()),
NonVirtualAlignment(CharUnits::One()),
- ZeroLengthBitfieldAlignment(CharUnits::Zero()), PrimaryBase(0),
+ ZeroLengthBitfield(0), PrimaryBase(0),
PrimaryBaseIsVirtual(false), FirstNearlyEmptyVBase(0) { }
void Layout(const RecordDecl *D);
@@ -1258,27 +1258,112 @@ 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.
const FieldDecl *LastFD = 0;
+ ZeroLengthBitfield = 0;
+ unsigned RemainingInAlignment = 0;
for (RecordDecl::field_iterator Field = D->field_begin(),
FieldEnd = D->field_end(); Field != FieldEnd; ++Field) {
if (IsMsStruct) {
- const FieldDecl *FD = (*Field);
- if (Context.ZeroBitfieldFollowsBitfield(FD, LastFD)) {
- // FIXME. Multiple zero bitfields may follow a bitfield.
- // set ZeroLengthBitfieldAlignment to max. of its
- // currrent and alignment of 'FD'.
- std::pair<CharUnits, CharUnits> FieldInfo =
- Context.getTypeInfoInChars(FD->getType());
- ZeroLengthBitfieldAlignment = FieldInfo.second;
- continue;
- }
+ FieldDecl *FD = (*Field);
+ if (Context.ZeroBitfieldFollowsBitfield(FD, LastFD))
+ ZeroLengthBitfield = FD;
// Zero-length bitfields following non-bitfield members are
// ignored:
- if (Context.ZeroBitfieldFollowsNonBitfield(FD, LastFD))
+ else if (Context.ZeroBitfieldFollowsNonBitfield(FD, LastFD))
continue;
+ // FIXME. streamline these conditions into a simple one.
+ else if (Context.BitfieldFollowsBitfield(FD, LastFD) ||
+ Context.BitfieldFollowsNoneBitfield(FD, LastFD) ||
+ Context.NoneBitfieldFollowsBitfield(FD, LastFD)) {
+ // 1) Adjacent bit fields are packed into the same 1-, 2-, or
+ // 4-byte allocation unit if the integral types are the same
+ // size and if the next bit field fits into the current
+ // allocation unit without crossing the boundary imposed by the
+ // common alignment requirements of the bit fields.
+ // 2) Establish a new alignment for a bitfield following
+ // a non-bitfield if size of their types differ.
+ // 3) Establish a new alignment for a non-bitfield following
+ // a bitfield if size of their types differ.
+ std::pair<uint64_t, unsigned> FieldInfo =
+ Context.getTypeInfo(FD->getType());
+ uint64_t TypeSize = FieldInfo.first;
+ unsigned FieldAlign = FieldInfo.second;
+ // This check is needed for 'long long' in -m32 mode.
+ if (TypeSize > FieldAlign)
+ FieldAlign = TypeSize;
+ FieldInfo = Context.getTypeInfo(LastFD->getType());
+ uint64_t TypeSizeLastFD = FieldInfo.first;
+ unsigned FieldAlignLastFD = FieldInfo.second;
+ // This check is needed for 'long long' in -m32 mode.
+ if (TypeSizeLastFD > FieldAlignLastFD)
+ FieldAlignLastFD = TypeSizeLastFD;
+
+ if (TypeSizeLastFD != TypeSize) {
+ if (RemainingInAlignment &&
+ LastFD && LastFD->isBitField() &&
+ LastFD->getBitWidth()->EvaluateAsInt(Context).getZExtValue()) {
+ // If previous field was a bitfield with some remaining unfilled
+ // bits, pad the field so current field starts on its type boundary.
+ uint64_t FieldOffset =
+ getDataSizeInBits() - UnfilledBitsInLastByte;
+ uint64_t NewSizeInBits = RemainingInAlignment + FieldOffset;
+ setDataSize(llvm::RoundUpToAlignment(NewSizeInBits,
+ Context.Target.getCharAlign()));
+ setSize(std::max(getSizeInBits(), getDataSizeInBits()));
+ RemainingInAlignment = 0;
+ }
+
+ uint64_t UnpaddedFieldOffset =
+ getDataSizeInBits() - UnfilledBitsInLastByte;
+ FieldAlign = std::max(FieldAlign, FieldAlignLastFD);
+
+ // The maximum field alignment overrides the aligned attribute.
+ if (!MaxFieldAlignment.isZero()) {
+ unsigned MaxFieldAlignmentInBits =
+ Context.toBits(MaxFieldAlignment);
+ FieldAlign = std::min(FieldAlign, MaxFieldAlignmentInBits);
+ }
+
+ uint64_t NewSizeInBits =
+ llvm::RoundUpToAlignment(UnpaddedFieldOffset, FieldAlign);
+ setDataSize(llvm::RoundUpToAlignment(NewSizeInBits,
+ Context.Target.getCharAlign()));
+ UnfilledBitsInLastByte = getDataSizeInBits() - NewSizeInBits;
+ setSize(std::max(getSizeInBits(), getDataSizeInBits()));
+ }
+ if (FD->isBitField()) {
+ uint64_t FieldSize =
+ FD->getBitWidth()->EvaluateAsInt(Context).getZExtValue();
+ assert (FieldSize > 0 && "LayoutFields - ms_struct layout");
+ if (RemainingInAlignment < FieldSize)
+ RemainingInAlignment = TypeSize - FieldSize;
+ else
+ RemainingInAlignment -= FieldSize;
+ }
+ }
+ else if (FD->isBitField()) {
+ uint64_t FieldSize =
+ FD->getBitWidth()->EvaluateAsInt(Context).getZExtValue();
+ std::pair<uint64_t, unsigned> FieldInfo =
+ Context.getTypeInfo(FD->getType());
+ uint64_t TypeSize = FieldInfo.first;
+ RemainingInAlignment = TypeSize - FieldSize;
+ }
LastFD = FD;
}
LayoutField(*Field);
}
+ if (IsMsStruct && RemainingInAlignment &&
+ LastFD && LastFD->isBitField() &&
+ LastFD->getBitWidth()->EvaluateAsInt(Context).getZExtValue()) {
+ // If we ended a bitfield before the full length of the type then
+ // pad the struct out to the full length of the last type.
+ uint64_t FieldOffset =
+ getDataSizeInBits() - UnfilledBitsInLastByte;
+ uint64_t NewSizeInBits = RemainingInAlignment + FieldOffset;
+ setDataSize(llvm::RoundUpToAlignment(NewSizeInBits,
+ Context.Target.getCharAlign()));
+ setSize(std::max(getSizeInBits(), getDataSizeInBits()));
+ }
}
void RecordLayoutBuilder::LayoutWideBitField(uint64_t FieldSize,
@@ -1355,6 +1440,27 @@ void RecordLayoutBuilder::LayoutBitField(const FieldDecl *D) {
std::pair<uint64_t, unsigned> FieldInfo = Context.getTypeInfo(D->getType());
uint64_t TypeSize = FieldInfo.first;
unsigned FieldAlign = FieldInfo.second;
+
+ // This check is needed for 'long long' in -m32 mode.
+ if (IsMsStruct && (TypeSize > FieldAlign))
+ FieldAlign = TypeSize;
+
+ if (ZeroLengthBitfield) {
+ // If a zero-length bitfield is inserted after a bitfield,
+ // and the alignment of the zero-length bitfield is
+ // greater than the member that follows it, `bar', `bar'
+ // will be aligned as the type of the zero-length bitfield.
+ if (ZeroLengthBitfield != D) {
+ std::pair<uint64_t, unsigned> FieldInfo =
+ Context.getTypeInfo(ZeroLengthBitfield->getType());
+ unsigned ZeroLengthBitfieldAlignment = FieldInfo.second;
+ // Ignore alignment of subsequent zero-length bitfields.
+ if ((ZeroLengthBitfieldAlignment > FieldAlign) || (FieldSize == 0))
+ FieldAlign = ZeroLengthBitfieldAlignment;
+ if (FieldSize)
+ ZeroLengthBitfield = 0;
+ }
+ }
if (FieldSize > TypeSize) {
LayoutWideBitField(FieldSize, TypeSize, FieldPacked, D);
@@ -1455,11 +1561,21 @@ void RecordLayoutBuilder::LayoutField(const FieldDecl *D) {
Context.getTypeInfoInChars(D->getType());
FieldSize = FieldInfo.first;
FieldAlign = FieldInfo.second;
- if (ZeroLengthBitfieldAlignment > FieldAlign)
- FieldAlign = ZeroLengthBitfieldAlignment;
- ZeroLengthBitfieldAlignment = CharUnits::Zero();
+
+ if (ZeroLengthBitfield) {
+ // If a zero-length bitfield is inserted after a bitfield,
+ // and the alignment of the zero-length bitfield is
+ // greater than the member that follows it, `bar', `bar'
+ // will be aligned as the type of the zero-length bitfield.
+ std::pair<CharUnits, CharUnits> FieldInfo =
+ Context.getTypeInfoInChars(ZeroLengthBitfield->getType());
+ CharUnits ZeroLengthBitfieldAlignment = FieldInfo.second;
+ if (ZeroLengthBitfieldAlignment > FieldAlign)
+ FieldAlign = ZeroLengthBitfieldAlignment;
+ ZeroLengthBitfield = 0;
+ }
- if (Context.getLangOptions().MSBitfields) {
+ if (Context.getLangOptions().MSBitfields || IsMsStruct) {
// If MS bitfield layout is required, figure out what type is being
// laid out and align the field to the width of that type.
@@ -1641,10 +1757,10 @@ RecordLayoutBuilder::ComputeKeyFunction(const CXXRecordDecl *RD) {
if (!RD->isPolymorphic())
return 0;
- // A class inside an anonymous namespace doesn't have a key function. (Or
+ // A class that is not externally visible doesn't have a key function. (Or
// at least, there's no point to assigning a key function to such a class;
// this doesn't affect the ABI.)
- if (RD->isInAnonymousNamespace())
+ if (RD->getLinkage() != ExternalLinkage)
return 0;
// Template instantiations don't have key functions,see Itanium C++ ABI 5.2.6.
diff --git a/lib/AST/StmtPrinter.cpp b/lib/AST/StmtPrinter.cpp
index 0d13502..87588e4 100644
--- a/lib/AST/StmtPrinter.cpp
+++ b/lib/AST/StmtPrinter.cpp
@@ -1297,7 +1297,7 @@ static const char *getTypeTraitName(UnaryTypeTrait UTT) {
case UTT_HasNothrowConstructor: return "__has_nothrow_constructor";
case UTT_HasNothrowCopy: return "__has_nothrow_copy";
case UTT_HasTrivialAssign: return "__has_trivial_assign";
- case UTT_HasTrivialConstructor: return "__has_trivial_constructor";
+ case UTT_HasTrivialDefaultConstructor: return "__has_trivial_constructor";
case UTT_HasTrivialCopy: return "__has_trivial_copy";
case UTT_HasTrivialDestructor: return "__has_trivial_destructor";
case UTT_HasVirtualDestructor: return "__has_virtual_destructor";
@@ -1329,6 +1329,7 @@ static const char *getTypeTraitName(UnaryTypeTrait UTT) {
case UTT_IsSigned: return "__is_signed";
case UTT_IsStandardLayout: return "__is_standard_layout";
case UTT_IsTrivial: return "__is_trivial";
+ case UTT_IsTriviallyCopyable: return "__is_trivially_copyable";
case UTT_IsUnion: return "__is_union";
case UTT_IsUnsigned: return "__is_unsigned";
case UTT_IsVoid: return "__is_void";
@@ -1498,6 +1499,13 @@ void StmtPrinter::VisitBlockDeclRefExpr(BlockDeclRefExpr *Node) {
void StmtPrinter::VisitOpaqueValueExpr(OpaqueValueExpr *Node) {}
+void StmtPrinter::VisitAsTypeExpr(AsTypeExpr *Node) {
+ OS << "__builtin_astype(";
+ PrintExpr(Node->getSrcExpr());
+ OS << ", " << Node->getType().getAsString();
+ OS << ")";
+}
+
//===----------------------------------------------------------------------===//
// Stmt method implementations
//===----------------------------------------------------------------------===//
diff --git a/lib/AST/StmtProfile.cpp b/lib/AST/StmtProfile.cpp
index 44818e8..b117cd9 100644
--- a/lib/AST/StmtProfile.cpp
+++ b/lib/AST/StmtProfile.cpp
@@ -679,6 +679,10 @@ void StmtProfiler::VisitCUDAKernelCallExpr(CUDAKernelCallExpr *S) {
VisitCallExpr(S);
}
+void StmtProfiler::VisitAsTypeExpr(AsTypeExpr *S) {
+ VisitExpr(S);
+}
+
void StmtProfiler::VisitCXXNamedCastExpr(CXXNamedCastExpr *S) {
VisitExplicitCastExpr(S);
}
diff --git a/lib/AST/Type.cpp b/lib/AST/Type.cpp
index 9eb497b..d2875528 100644
--- a/lib/AST/Type.cpp
+++ b/lib/AST/Type.cpp
@@ -517,7 +517,7 @@ bool Type::isIntegerType() const {
if (const EnumType *ET = dyn_cast<EnumType>(CanonicalType))
// Incomplete enum types are not treated as integer types.
// FIXME: In C++, enum types are never integer types.
- return ET->getDecl()->isComplete();
+ return ET->getDecl()->isComplete() && !ET->getDecl()->isScoped();
return false;
}
@@ -641,13 +641,27 @@ bool Type::isSignedIntegerType() const {
if (const EnumType *ET = dyn_cast<EnumType>(CanonicalType)) {
// Incomplete enum types are not treated as integer types.
// FIXME: In C++, enum types are never integer types.
- if (ET->getDecl()->isComplete())
+ if (ET->getDecl()->isComplete() && !ET->getDecl()->isScoped())
return ET->getDecl()->getIntegerType()->isSignedIntegerType();
}
return false;
}
+bool Type::isSignedIntegerOrEnumerationType() const {
+ if (const BuiltinType *BT = dyn_cast<BuiltinType>(CanonicalType)) {
+ return BT->getKind() >= BuiltinType::Char_S &&
+ BT->getKind() <= BuiltinType::Int128;
+ }
+
+ if (const EnumType *ET = dyn_cast<EnumType>(CanonicalType)) {
+ if (ET->getDecl()->isComplete())
+ return ET->getDecl()->getIntegerType()->isSignedIntegerType();
+ }
+
+ return false;
+}
+
bool Type::hasSignedIntegerRepresentation() const {
if (const VectorType *VT = dyn_cast<VectorType>(CanonicalType))
return VT->getElementType()->isSignedIntegerType();
@@ -667,13 +681,27 @@ bool Type::isUnsignedIntegerType() const {
if (const EnumType *ET = dyn_cast<EnumType>(CanonicalType)) {
// Incomplete enum types are not treated as integer types.
// FIXME: In C++, enum types are never integer types.
- if (ET->getDecl()->isComplete())
+ if (ET->getDecl()->isComplete() && !ET->getDecl()->isScoped())
return ET->getDecl()->getIntegerType()->isUnsignedIntegerType();
}
return false;
}
+bool Type::isUnsignedIntegerOrEnumerationType() const {
+ if (const BuiltinType *BT = dyn_cast<BuiltinType>(CanonicalType)) {
+ return BT->getKind() >= BuiltinType::Bool &&
+ BT->getKind() <= BuiltinType::UInt128;
+ }
+
+ if (const EnumType *ET = dyn_cast<EnumType>(CanonicalType)) {
+ if (ET->getDecl()->isComplete())
+ return ET->getDecl()->getIntegerType()->isUnsignedIntegerType();
+ }
+
+ return false;
+}
+
bool Type::hasUnsignedIntegerRepresentation() const {
if (const VectorType *VT = dyn_cast<VectorType>(CanonicalType))
return VT->getElementType()->isUnsignedIntegerType();
@@ -954,10 +982,37 @@ bool Type::isTrivialType() const {
if (const RecordType *RT = BaseTy->getAs<RecordType>()) {
if (const CXXRecordDecl *ClassDecl =
dyn_cast<CXXRecordDecl>(RT->getDecl())) {
- // C++0x [class]p5:
- // A trivial class is a class that has a trivial default constructor
- if (!ClassDecl->hasTrivialConstructor()) return false;
- // and is trivially copyable.
+ if (!ClassDecl->isTrivial()) return false;
+ }
+
+ return true;
+ }
+
+ // No other types can match.
+ return false;
+}
+
+bool Type::isTriviallyCopyableType() const {
+ if (isDependentType())
+ return false;
+
+ // C++0x [basic.types]p9
+ // Scalar types, trivially copyable class types, arrays of such types, and
+ // cv-qualified versions of these types are collectively called trivial
+ // types.
+ const Type *BaseTy = getBaseElementTypeUnsafe();
+ assert(BaseTy && "NULL element type");
+
+ // Return false for incomplete types after skipping any incomplete array types
+ // which are expressly allowed by the standard and thus our API.
+ if (BaseTy->isIncompleteType())
+ return false;
+
+ // As an extension, Clang treats vector types as Scalar types.
+ if (BaseTy->isScalarType() || BaseTy->isVectorType()) return true;
+ if (const RecordType *RT = BaseTy->getAs<RecordType>()) {
+ if (const CXXRecordDecl *ClassDecl =
+ dyn_cast<CXXRecordDecl>(RT->getDecl())) {
if (!ClassDecl->isTriviallyCopyable()) return false;
}
@@ -1027,11 +1082,7 @@ bool Type::isCXX11PODType() const {
dyn_cast<CXXRecordDecl>(RT->getDecl())) {
// C++11 [class]p10:
// A POD struct is a non-union class that is both a trivial class [...]
- // C++11 [class]p5:
- // A trivial class is a class that has a trivial default constructor
- if (!ClassDecl->hasTrivialConstructor()) return false;
- // and is trivially copyable.
- if (!ClassDecl->isTriviallyCopyable()) return false;
+ if (!ClassDecl->isTrivial()) return false;
// C++11 [class]p10:
// A POD struct is a non-union class that is both a trivial class and
@@ -1484,6 +1535,16 @@ static TagDecl *getInterestingTagDecl(TagDecl *decl) {
return decl;
}
+UnaryTransformType::UnaryTransformType(QualType BaseType,
+ QualType UnderlyingType,
+ UTTKind UKind,
+ QualType CanonicalType)
+ : Type(UnaryTransform, CanonicalType, UnderlyingType->isDependentType(),
+ UnderlyingType->isVariablyModifiedType(),
+ BaseType->containsUnexpandedParameterPack())
+ , BaseType(BaseType), UnderlyingType(UnderlyingType), UKind(UKind)
+{}
+
TagDecl *TagType::getDecl() const {
return getInterestingTagDecl(decl);
}
@@ -1559,13 +1620,13 @@ anyDependentTemplateArguments(const TemplateArgument *Args, unsigned N) {
TemplateSpecializationType::
TemplateSpecializationType(TemplateName T,
- const TemplateArgument *Args,
- unsigned NumArgs, QualType Canon)
+ const TemplateArgument *Args, unsigned NumArgs,
+ QualType Canon, QualType AliasedType)
: Type(TemplateSpecialization,
Canon.isNull()? QualType(this, 0) : Canon,
- T.isDependent(), false, T.containsUnexpandedParameterPack()),
- Template(T), NumArgs(NumArgs)
-{
+ Canon.isNull()? T.isDependent() : Canon->isDependentType(),
+ false, T.containsUnexpandedParameterPack()),
+ Template(T), NumArgs(NumArgs) {
assert(!T.getAsDependentTemplateName() &&
"Use DependentTemplateSpecializationType for dependent template-name");
assert((!Canon.isNull() ||
@@ -1576,7 +1637,12 @@ TemplateSpecializationType(TemplateName T,
= reinterpret_cast<TemplateArgument *>(this + 1);
for (unsigned Arg = 0; Arg < NumArgs; ++Arg) {
// Update dependent and variably-modified bits.
- if (Args[Arg].isDependent())
+ // If the canonical type exists and is non-dependent, the template
+ // specialization type can be non-dependent even if one of the type
+ // arguments is. Given:
+ // template<typename T> using U = int;
+ // U<T> is always non-dependent, irrespective of the type T.
+ if (Canon.isNull() && Args[Arg].isDependent())
setDependent();
if (Args[Arg].getKind() == TemplateArgument::Type &&
Args[Arg].getAsType()->isVariablyModifiedType())
@@ -1586,6 +1652,15 @@ TemplateSpecializationType(TemplateName T,
new (&TemplateArgs[Arg]) TemplateArgument(Args[Arg]);
}
+
+ // Store the aliased type if this is a type alias template specialization.
+ bool IsTypeAlias = !AliasedType.isNull();
+ assert(IsTypeAlias == isTypeAlias() &&
+ "allocated wrong size for type alias");
+ if (IsTypeAlias) {
+ TemplateArgument *Begin = reinterpret_cast<TemplateArgument *>(this + 1);
+ *reinterpret_cast<QualType*>(Begin + getNumArgs()) = AliasedType;
+ }
}
void
@@ -1599,6 +1674,11 @@ TemplateSpecializationType::Profile(llvm::FoldingSetNodeID &ID,
Args[Idx].Profile(ID, Context);
}
+bool TemplateSpecializationType::isTypeAlias() const {
+ TemplateDecl *D = Template.getAsTemplateDecl();
+ return D && isa<TypeAliasTemplateDecl>(D);
+}
+
QualType
QualifierCollector::apply(const ASTContext &Context, QualType QT) const {
if (!hasNonFastQualifiers())
diff --git a/lib/AST/TypePrinter.cpp b/lib/AST/TypePrinter.cpp
index 0c5df7f..4519606 100644
--- a/lib/AST/TypePrinter.cpp
+++ b/lib/AST/TypePrinter.cpp
@@ -94,6 +94,7 @@ void TypePrinter::print(const Type *T, Qualifiers Quals, std::string &buffer) {
case Type::TypeOfExpr:
case Type::TypeOf:
case Type::Decltype:
+ case Type::UnaryTransform:
case Type::Record:
case Type::Enum:
case Type::Elaborated:
@@ -512,6 +513,20 @@ void TypePrinter::printDecltype(const DecltypeType *T, std::string &S) {
S = "decltype(" + s.str() + ")" + S;
}
+void TypePrinter::printUnaryTransform(const UnaryTransformType *T,
+ std::string &S) {
+ if (!S.empty())
+ S = ' ' + S;
+ std::string Str;
+ print(T->getBaseType(), Str);
+
+ switch (T->getUTTKind()) {
+ case UnaryTransformType::EnumUnderlyingType:
+ S = "__underlying_type(" + Str + ")" + S;
+ break;
+ }
+}
+
void TypePrinter::printAuto(const AutoType *T, std::string &S) {
// If the type has been deduced, do not print 'auto'.
if (T->isDeduced()) {
@@ -963,7 +978,7 @@ TemplateSpecializationType::PrintTemplateArgumentList(
SpecString += '<';
for (unsigned Arg = 0; Arg < NumArgs; ++Arg) {
- if (SpecString.size() > !SkipBrackets)
+ if (SpecString.size() > unsigned(!SkipBrackets))
SpecString += ", ";
// Print the argument into a string.
diff --git a/lib/Analysis/AnalysisContext.cpp b/lib/Analysis/AnalysisContext.cpp
index ddc5e88..678f02f 100644
--- a/lib/Analysis/AnalysisContext.cpp
+++ b/lib/Analysis/AnalysisContext.cpp
@@ -78,16 +78,16 @@ void AnalysisContext::registerForcedBlockExpression(const Stmt *stmt) {
if (!forcedBlkExprs)
forcedBlkExprs = new CFG::BuildOptions::ForcedBlkExprs();
// Default construct an entry for 'stmt'.
- if (const ParenExpr *pe = dyn_cast<ParenExpr>(stmt))
- stmt = pe->IgnoreParens();
+ if (const Expr *e = dyn_cast<Expr>(stmt))
+ stmt = e->IgnoreParens();
(void) (*forcedBlkExprs)[stmt];
}
const CFGBlock *
AnalysisContext::getBlockForRegisteredExpression(const Stmt *stmt) {
assert(forcedBlkExprs);
- if (const ParenExpr *pe = dyn_cast<ParenExpr>(stmt))
- stmt = pe->IgnoreParens();
+ if (const Expr *e = dyn_cast<Expr>(stmt))
+ stmt = e->IgnoreParens();
CFG::BuildOptions::ForcedBlkExprs::const_iterator itr =
forcedBlkExprs->find(stmt);
assert(itr != forcedBlkExprs->end());
diff --git a/lib/Analysis/CFG.cpp b/lib/Analysis/CFG.cpp
index de16334..3e54020 100644
--- a/lib/Analysis/CFG.cpp
+++ b/lib/Analysis/CFG.cpp
@@ -320,7 +320,6 @@ private:
AddStmtChoice asc);
CFGBlock *VisitCXXTemporaryObjectExpr(CXXTemporaryObjectExpr *C,
AddStmtChoice asc);
- CFGBlock *VisitCXXMemberCallExpr(CXXMemberCallExpr *C, AddStmtChoice asc);
CFGBlock *VisitCallExpr(CallExpr *C, AddStmtChoice asc);
CFGBlock *VisitCaseStmt(CaseStmt *C);
CFGBlock *VisitChooseExpr(ChooseExpr *C, AddStmtChoice asc);
@@ -398,6 +397,8 @@ private:
if (alwaysAdd(S))
cachedEntry->second = B;
+ // All block-level expressions should have already been IgnoreParens()ed.
+ assert(!isa<Expr>(S) || cast<Expr>(S)->IgnoreParens() == S);
B->appendStmt(const_cast<Stmt*>(S), cfg->getBumpVectorContext());
}
void appendInitializer(CFGBlock *B, CXXCtorInitializer *I) {
@@ -444,7 +445,7 @@ private:
return Result.Val.getInt().getBoolValue();
if (Result.Val.isLValue()) {
- Expr *e = Result.Val.getLValueBase();
+ const Expr *e = Result.Val.getLValueBase();
const CharUnits &c = Result.Val.getLValueOffset();
if (!e && c.isZero())
return false;
@@ -842,11 +843,14 @@ void CFGBuilder::prependAutomaticObjDtorsWithTerminator(CFGBlock* Blk,
/// blocks for ternary operators, &&, and ||. We also process "," and
/// DeclStmts (which may contain nested control-flow).
CFGBlock* CFGBuilder::Visit(Stmt * S, AddStmtChoice asc) {
-tryAgain:
if (!S) {
badCFG = true;
return 0;
}
+
+ if (Expr *E = dyn_cast<Expr>(S))
+ S = E->IgnoreParens();
+
switch (S->getStmtClass()) {
default:
return VisitStmt(S, asc);
@@ -868,6 +872,7 @@ tryAgain:
case Stmt::CallExprClass:
case Stmt::CXXOperatorCallExprClass:
+ case Stmt::CXXMemberCallExprClass:
return VisitCallExpr(cast<CallExpr>(S), asc);
case Stmt::CaseStmtClass:
@@ -903,9 +908,6 @@ tryAgain:
case Stmt::CXXTemporaryObjectExprClass:
return VisitCXXTemporaryObjectExpr(cast<CXXTemporaryObjectExpr>(S), asc);
- case Stmt::CXXMemberCallExprClass:
- return VisitCXXMemberCallExpr(cast<CXXMemberCallExpr>(S), asc);
-
case Stmt::CXXThrowExprClass:
return VisitCXXThrowExpr(cast<CXXThrowExpr>(S));
@@ -960,10 +962,6 @@ tryAgain:
case Stmt::ObjCForCollectionStmtClass:
return VisitObjCForCollectionStmt(cast<ObjCForCollectionStmt>(S));
- case Stmt::ParenExprClass:
- S = cast<ParenExpr>(S)->getSubExpr();
- goto tryAgain;
-
case Stmt::NullStmtClass:
return Block;
@@ -1153,12 +1151,19 @@ static bool CanThrow(Expr *E, ASTContext &Ctx) {
}
CFGBlock *CFGBuilder::VisitCallExpr(CallExpr *C, AddStmtChoice asc) {
- // If this is a call to a no-return function, this stops the block here.
- bool NoReturn = false;
- if (getFunctionExtInfo(*C->getCallee()->getType()).getNoReturn()) {
- NoReturn = true;
+ // Compute the callee type.
+ QualType calleeType = C->getCallee()->getType();
+ if (calleeType == Context->BoundMemberTy) {
+ QualType boundType = Expr::findBoundMemberType(C->getCallee());
+
+ // We should only get a null bound type if processing a dependent
+ // CFG. Recover by assuming nothing.
+ if (!boundType.isNull()) calleeType = boundType;
}
+ // If this is a call to a no-return function, this stops the block here.
+ bool NoReturn = getFunctionExtInfo(*calleeType).getNoReturn();
+
bool AddEHEdge = false;
// Languages without exceptions are assumed to not throw.
@@ -1314,6 +1319,12 @@ CFGBlock *CFGBuilder::VisitConditionalOperator(AbstractConditionalOperator *C,
}
CFGBlock *CFGBuilder::VisitDeclStmt(DeclStmt *DS) {
+ // Check if the Decl is for an __label__. If so, elide it from the
+ // CFG entirely.
+ if (isa<LabelDecl>(*DS->decl_begin()))
+ return Block;
+
+ // This case also handles static_asserts.
if (DS->isSingleDecl())
return VisitDeclSubExpr(DS);
@@ -1346,7 +1357,14 @@ CFGBlock *CFGBuilder::VisitDeclStmt(DeclStmt *DS) {
/// DeclStmts and initializers in them.
CFGBlock *CFGBuilder::VisitDeclSubExpr(DeclStmt* DS) {
assert(DS->isSingleDecl() && "Can handle single declarations only.");
-
+ Decl *D = DS->getSingleDecl();
+
+ if (isa<StaticAssertDecl>(D)) {
+ // static_asserts aren't added to the CFG because they do not impact
+ // runtime semantics.
+ return Block;
+ }
+
VarDecl *VD = dyn_cast<VarDecl>(DS->getSingleDecl());
if (!VD) {
@@ -2686,13 +2704,6 @@ CFGBlock *CFGBuilder::VisitCXXTemporaryObjectExpr(CXXTemporaryObjectExpr *C,
return VisitChildren(C);
}
-CFGBlock *CFGBuilder::VisitCXXMemberCallExpr(CXXMemberCallExpr *C,
- AddStmtChoice asc) {
- autoCreateBlock();
- appendStmt(Block, C);
- return VisitChildren(C);
-}
-
CFGBlock *CFGBuilder::VisitImplicitCastExpr(ImplicitCastExpr *E,
AddStmtChoice asc) {
if (asc.alwaysAdd(*this, E)) {
@@ -3039,6 +3050,7 @@ static BlkExprMapTy* PopulateBlkExprMap(CFG& cfg) {
if (!CS)
continue;
if (Expr* Exp = dyn_cast<Expr>(CS->getStmt())) {
+ assert((Exp->IgnoreParens() == Exp) && "No parens on block-level exps");
if (BinaryOperator* B = dyn_cast<BinaryOperator>(Exp)) {
// Assignment expressions that are not nested within another
@@ -3046,13 +3058,16 @@ static BlkExprMapTy* PopulateBlkExprMap(CFG& cfg) {
// another expression.
if (B->isAssignmentOp() && !SubExprAssignments.count(Exp))
continue;
- } else if (const StmtExpr* Terminator = dyn_cast<StmtExpr>(Exp)) {
+ } else if (const StmtExpr* SE = dyn_cast<StmtExpr>(Exp)) {
// Special handling for statement expressions. The last statement in
// the statement expression is also a block-level expr.
- const CompoundStmt* C = Terminator->getSubStmt();
+ const CompoundStmt* C = SE->getSubStmt();
if (!C->body_empty()) {
+ const Stmt *Last = C->body_back();
+ if (const Expr *LastEx = dyn_cast<Expr>(Last))
+ Last = LastEx->IgnoreParens();
unsigned x = M->size();
- (*M)[C->body_back()] = x;
+ (*M)[Last] = x;
}
}
@@ -3066,8 +3081,8 @@ static BlkExprMapTy* PopulateBlkExprMap(CFG& cfg) {
Stmt* S = (*I)->getTerminatorCondition();
if (S && M->find(S) == M->end()) {
- unsigned x = M->size();
- (*M)[S] = x;
+ unsigned x = M->size();
+ (*M)[S] = x;
}
}
diff --git a/lib/Analysis/CocoaConventions.cpp b/lib/Analysis/CocoaConventions.cpp
index 4c62f36..946c38c 100644
--- a/lib/Analysis/CocoaConventions.cpp
+++ b/lib/Analysis/CocoaConventions.cpp
@@ -44,6 +44,7 @@ cocoa::NamingConvention cocoa::deriveNamingConvention(Selector S) {
case OMF_release:
case OMF_retain:
case OMF_retainCount:
+ case OMF_self:
return NoConvention;
case OMF_init:
diff --git a/lib/Analysis/LiveVariables.cpp b/lib/Analysis/LiveVariables.cpp
index 303dc0f..7b36f85 100644
--- a/lib/Analysis/LiveVariables.cpp
+++ b/lib/Analysis/LiveVariables.cpp
@@ -157,7 +157,7 @@ void TransferFuncs::Visit(Stmt *S) {
}
else {
// For block-level expressions, mark that they are live.
- LiveState(S,AD) = Alive;
+ LiveState(S, AD) = Alive;
}
}
diff --git a/lib/Analysis/UninitializedValues.cpp b/lib/Analysis/UninitializedValues.cpp
index 88a2db7..e80e282 100644
--- a/lib/Analysis/UninitializedValues.cpp
+++ b/lib/Analysis/UninitializedValues.cpp
@@ -14,7 +14,7 @@
#include <utility>
#include "llvm/ADT/Optional.h"
#include "llvm/ADT/SmallVector.h"
-#include "llvm/ADT/BitVector.h"
+#include "llvm/ADT/PackedVector.h"
#include "llvm/ADT/DenseMap.h"
#include "clang/AST/Decl.h"
#include "clang/Analysis/CFG.h"
@@ -93,39 +93,8 @@ static bool isAlwaysUninit(const Value v) {
}
namespace {
-class ValueVector {
- llvm::BitVector vec;
-public:
- ValueVector() {}
- ValueVector(unsigned size) : vec(size << 1) {}
- void resize(unsigned n) { vec.resize(n << 1); }
- void merge(const ValueVector &rhs) { vec |= rhs.vec; }
- bool operator!=(const ValueVector &rhs) const { return vec != rhs.vec; }
- void reset() { vec.reset(); }
-
- class reference {
- ValueVector &vv;
- const unsigned idx;
-
- reference(); // Undefined
- public:
- reference(ValueVector &vv, unsigned idx) : vv(vv), idx(idx) {}
- ~reference() {}
-
- reference &operator=(Value v) {
- vv.vec[idx << 1] = (((unsigned) v) & 0x1) ? true : false;
- vv.vec[(idx << 1) | 1] = (((unsigned) v) & 0x2) ? true : false;
- return *this;
- }
- operator Value() {
- unsigned x = (vv.vec[idx << 1] ? 1 : 0) | (vv.vec[(idx << 1) | 1] ? 2 :0);
- return (Value) x;
- }
- };
-
- reference operator[](unsigned idx) { return reference(*this, idx); }
-};
+typedef llvm::PackedVector<Value, 2> ValueVector;
typedef std::pair<ValueVector *, ValueVector *> BVPair;
class CFGBlockValues {
@@ -214,11 +183,15 @@ static BinaryOperator *getLogicalOperatorInChain(const CFGBlock *block) {
if (!b || !b->isLogicalOp())
return 0;
- if (block->pred_size() == 2 &&
- ((block->succ_size() == 2 && block->getTerminatorCondition() == b) ||
- block->size() == 1))
- return b;
-
+ if (block->pred_size() == 2) {
+ if (block->getTerminatorCondition() == b) {
+ if (block->succ_size() == 2)
+ return b;
+ }
+ else if (block->size() == 1)
+ return b;
+ }
+
return 0;
}
@@ -255,7 +228,7 @@ void CFGBlockValues::mergeIntoScratch(ValueVector const &source,
if (isFirst)
scratch = source;
else
- scratch.merge(source);
+ scratch |= source;
}
#if 0
static void printVector(const CFGBlock *block, ValueVector &bv,
diff --git a/lib/Basic/Diagnostic.cpp b/lib/Basic/Diagnostic.cpp
index e8cd218..11887ab 100644
--- a/lib/Basic/Diagnostic.cpp
+++ b/lib/Basic/Diagnostic.cpp
@@ -212,6 +212,42 @@ void Diagnostic::setDiagnosticMapping(diag::kind Diag, diag::Mapping Map,
FullSourceLoc(Loc, *SourceMgr)));
}
+void Diagnostic::Report(const StoredDiagnostic &storedDiag) {
+ assert(CurDiagID == ~0U && "Multiple diagnostics in flight at once!");
+
+ CurDiagLoc = storedDiag.getLocation();
+ CurDiagID = storedDiag.getID();
+ NumDiagArgs = 0;
+
+ NumDiagRanges = storedDiag.range_size();
+ assert(NumDiagRanges < sizeof(DiagRanges)/sizeof(DiagRanges[0]) &&
+ "Too many arguments to diagnostic!");
+ unsigned i = 0;
+ for (StoredDiagnostic::range_iterator
+ RI = storedDiag.range_begin(),
+ RE = storedDiag.range_end(); RI != RE; ++RI)
+ DiagRanges[i++] = *RI;
+
+ NumFixItHints = storedDiag.fixit_size();
+ assert(NumFixItHints < Diagnostic::MaxFixItHints && "Too many fix-it hints!");
+ i = 0;
+ for (StoredDiagnostic::fixit_iterator
+ FI = storedDiag.fixit_begin(),
+ FE = storedDiag.fixit_end(); FI != FE; ++FI)
+ FixItHints[i++] = *FI;
+
+ assert(Client && "DiagnosticClient not set!");
+ Level DiagLevel = storedDiag.getLevel();
+ DiagnosticInfo Info(this, storedDiag.getMessage());
+ Client->HandleDiagnostic(DiagLevel, Info);
+ if (Client->IncludeInDiagnosticCounts()) {
+ if (DiagLevel == Diagnostic::Warning)
+ ++NumWarnings;
+ }
+
+ CurDiagID = ~0U;
+}
+
void DiagnosticBuilder::FlushCounts() {
DiagObj->NumDiagArgs = NumArgs;
DiagObj->NumDiagRanges = NumRanges;
@@ -486,10 +522,15 @@ static void HandlePluralModifier(const DiagnosticInfo &DInfo, unsigned ValNo,
/// array.
void DiagnosticInfo::
FormatDiagnostic(llvm::SmallVectorImpl<char> &OutStr) const {
- const char *DiagStr = getDiags()->getDiagnosticIDs()->getDescription(getID());
- const char *DiagEnd = DiagStr+strlen(DiagStr);
+ if (!StoredDiagMessage.empty()) {
+ OutStr.append(StoredDiagMessage.begin(), StoredDiagMessage.end());
+ return;
+ }
+
+ llvm::StringRef Diag =
+ getDiags()->getDiagnosticIDs()->getDescription(getID());
- FormatDiagnostic(DiagStr, DiagEnd, OutStr);
+ FormatDiagnostic(Diag.begin(), Diag.end(), OutStr);
}
void DiagnosticInfo::
diff --git a/lib/Basic/DiagnosticIDs.cpp b/lib/Basic/DiagnosticIDs.cpp
index b4dd575..6d7e320 100644
--- a/lib/Basic/DiagnosticIDs.cpp
+++ b/lib/Basic/DiagnosticIDs.cpp
@@ -45,14 +45,37 @@ struct StaticDiagInfoRec {
unsigned SFINAE : 1;
unsigned AccessControl : 1;
unsigned Category : 5;
-
- const char *Name;
-
- const char *Description;
- const char *OptionGroup;
- const char *BriefExplanation;
- const char *FullExplanation;
+ uint8_t NameLen;
+ uint8_t OptionGroupLen;
+
+ uint16_t DescriptionLen;
+ uint16_t BriefExplanationLen;
+ uint16_t FullExplanationLen;
+
+ const char *NameStr;
+ const char *OptionGroupStr;
+
+ const char *DescriptionStr;
+ const char *BriefExplanationStr;
+ const char *FullExplanationStr;
+
+ llvm::StringRef getName() const {
+ return llvm::StringRef(NameStr, NameLen);
+ }
+ llvm::StringRef getOptionGroup() const {
+ return llvm::StringRef(OptionGroupStr, OptionGroupLen);
+ }
+
+ llvm::StringRef getDescription() const {
+ return llvm::StringRef(DescriptionStr, DescriptionLen);
+ }
+ llvm::StringRef getBriefExplanation() const {
+ return llvm::StringRef(BriefExplanationStr, BriefExplanationLen);
+ }
+ llvm::StringRef getFullExplanation() const {
+ return llvm::StringRef(FullExplanationStr, FullExplanationLen);
+ }
bool operator<(const StaticDiagInfoRec &RHS) const {
return DiagID < RHS.DiagID;
@@ -60,27 +83,42 @@ struct StaticDiagInfoRec {
};
struct StaticDiagNameIndexRec {
- const char *Name;
+ const char *NameStr;
unsigned short DiagID;
-
+ uint8_t NameLen;
+
+ llvm::StringRef getName() const {
+ return llvm::StringRef(NameStr, NameLen);
+ }
+
bool operator<(const StaticDiagNameIndexRec &RHS) const {
- assert(Name && RHS.Name && "Null Diagnostic Name");
- return strcmp(Name, RHS.Name) == -1;
+ return getName() < RHS.getName();
}
bool operator==(const StaticDiagNameIndexRec &RHS) const {
- assert(Name && RHS.Name && "Null Diagnostic Name");
- return strcmp(Name, RHS.Name) == 0;
+ return getName() == RHS.getName();
}
};
-}
+template <size_t SizeOfStr, typename FieldType>
+class StringSizerHelper {
+ char FIELD_TOO_SMALL[SizeOfStr <= FieldType(~0U) ? 1 : -1];
+public:
+ enum { Size = SizeOfStr };
+};
+
+} // namespace anonymous
+
+#define STR_SIZE(str, fieldTy) StringSizerHelper<sizeof(str)-1, fieldTy>::Size
static const StaticDiagInfoRec StaticDiagInfo[] = {
-#define DIAG(ENUM,CLASS,DEFAULT_MAPPING,DESC,GROUP, \
- SFINAE,ACCESS,CATEGORY,BRIEF,FULL) \
- { diag::ENUM, DEFAULT_MAPPING, CLASS, SFINAE, \
- ACCESS, CATEGORY, #ENUM, DESC, GROUP, BRIEF, FULL },
+#define DIAG(ENUM,CLASS,DEFAULT_MAPPING,DESC,GROUP, \
+ SFINAE,ACCESS,CATEGORY,BRIEF,FULL) \
+ { diag::ENUM, DEFAULT_MAPPING, CLASS, SFINAE, ACCESS, CATEGORY, \
+ STR_SIZE(#ENUM, uint8_t), STR_SIZE(GROUP, uint8_t), \
+ STR_SIZE(DESC, uint16_t), STR_SIZE(BRIEF, uint16_t), \
+ STR_SIZE(FULL, uint16_t), \
+ #ENUM, GROUP, DESC, BRIEF, FULL },
#include "clang/Basic/DiagnosticCommonKinds.inc"
#include "clang/Basic/DiagnosticDriverKinds.inc"
#include "clang/Basic/DiagnosticFrontendKinds.inc"
@@ -90,7 +128,7 @@ static const StaticDiagInfoRec StaticDiagInfo[] = {
#include "clang/Basic/DiagnosticSemaKinds.inc"
#include "clang/Basic/DiagnosticAnalysisKinds.inc"
#undef DIAG
- { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
+ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
};
static const unsigned StaticDiagInfoSize =
@@ -98,10 +136,10 @@ static const unsigned StaticDiagInfoSize =
/// To be sorted before first use (since it's splitted among multiple files)
static StaticDiagNameIndexRec StaticDiagNameIndex[] = {
-#define DIAG_NAME_INDEX(ENUM) { #ENUM, diag::ENUM },
+#define DIAG_NAME_INDEX(ENUM) { #ENUM, diag::ENUM, STR_SIZE(#ENUM, uint8_t) },
#include "clang/Basic/DiagnosticIndexName.inc"
#undef DIAG_NAME_INDEX
- { 0, 0 }
+ { 0, 0, 0 }
};
static const unsigned StaticDiagNameIndexSize =
@@ -127,7 +165,7 @@ static const StaticDiagInfoRec *GetDiagInfo(unsigned DiagID) {
#endif
// Search the diagnostic table with a binary search.
- StaticDiagInfoRec Find = { DiagID, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
+ StaticDiagInfoRec Find = { DiagID, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,0,0,0 };
const StaticDiagInfoRec *Found =
std::lower_bound(StaticDiagInfo, StaticDiagInfo + StaticDiagInfoSize, Find);
@@ -147,10 +185,10 @@ static unsigned GetDefaultDiagMapping(unsigned DiagID) {
/// getWarningOptionForDiag - Return the lowest-level warning option that
/// enables the specified diagnostic. If there is no -Wfoo flag that controls
/// the diagnostic, this returns null.
-const char *DiagnosticIDs::getWarningOptionForDiag(unsigned DiagID) {
+llvm::StringRef DiagnosticIDs::getWarningOptionForDiag(unsigned DiagID) {
if (const StaticDiagInfoRec *Info = GetDiagInfo(DiagID))
- return Info->OptionGroup;
- return 0;
+ return Info->getOptionGroup();
+ return llvm::StringRef();
}
/// getCategoryNumberForDiag - Return the category number that a specified
@@ -161,23 +199,36 @@ unsigned DiagnosticIDs::getCategoryNumberForDiag(unsigned DiagID) {
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 *DiagnosticIDs::getCategoryNameFromID(unsigned CategoryID) {
- // Second the table of options, sorted by name for fast binary lookup.
- static const char *CategoryNameTable[] = {
+// The diagnostic category names.
+struct StaticDiagCategoryRec {
+ const char *NameStr;
+ uint8_t NameLen;
+
+ llvm::StringRef getName() const {
+ return llvm::StringRef(NameStr, NameLen);
+ }
+};
+
+static StaticDiagCategoryRec CategoryNameTable[] = {
#define GET_CATEGORY_TABLE
-#define CATEGORY(X) X,
+#define CATEGORY(X) { X, STR_SIZE(X, uint8_t) },
#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];
+ { 0, 0 }
+};
+
+/// getNumberOfCategories - Return the number of categories
+unsigned DiagnosticIDs::getNumberOfCategories() {
+ return sizeof(CategoryNameTable) / sizeof(CategoryNameTable[0])-1;
+}
+
+/// getCategoryNameFromID - Given a category ID, return the name of the
+/// category, an empty string if CategoryID is zero, or null if CategoryID is
+/// invalid.
+llvm::StringRef DiagnosticIDs::getCategoryNameFromID(unsigned CategoryID) {
+ if (CategoryID >= getNumberOfCategories())
+ return llvm::StringRef();
+ return CategoryNameTable[CategoryID].getName();
}
@@ -202,25 +253,25 @@ DiagnosticIDs::getDiagnosticSFINAEResponse(unsigned DiagID) {
}
/// getName - Given a diagnostic ID, return its name
-const char *DiagnosticIDs::getName(unsigned DiagID) {
+llvm::StringRef DiagnosticIDs::getName(unsigned DiagID) {
if (const StaticDiagInfoRec *Info = GetDiagInfo(DiagID))
- return Info->Name;
- return 0;
+ return Info->getName();
+ return llvm::StringRef();
}
/// getIdFromName - Given a diagnostic name, return its ID, or 0
-unsigned DiagnosticIDs::getIdFromName(char const *Name) {
+unsigned DiagnosticIDs::getIdFromName(llvm::StringRef Name) {
StaticDiagNameIndexRec *StaticDiagNameIndexEnd =
StaticDiagNameIndex + StaticDiagNameIndexSize;
- if (Name == 0) { return diag::DIAG_UPPER_LIMIT; }
+ if (Name.empty()) { return diag::DIAG_UPPER_LIMIT; }
- StaticDiagNameIndexRec Find = { Name, 0 };
+ StaticDiagNameIndexRec Find = { Name.data(), 0, Name.size() };
const StaticDiagNameIndexRec *Found =
std::lower_bound( StaticDiagNameIndex, StaticDiagNameIndexEnd, Find);
if (Found == StaticDiagNameIndexEnd ||
- strcmp(Found->Name, Name) != 0)
+ Found->getName() != Name)
return diag::DIAG_UPPER_LIMIT;
return Found->DiagID;
@@ -228,18 +279,18 @@ unsigned DiagnosticIDs::getIdFromName(char const *Name) {
/// getBriefExplanation - Given a diagnostic ID, return a brief explanation
/// of the issue
-const char *DiagnosticIDs::getBriefExplanation(unsigned DiagID) {
+llvm::StringRef DiagnosticIDs::getBriefExplanation(unsigned DiagID) {
if (const StaticDiagInfoRec *Info = GetDiagInfo(DiagID))
- return Info->BriefExplanation;
- return 0;
+ return Info->getBriefExplanation();
+ return llvm::StringRef();
}
/// getFullExplanation - Given a diagnostic ID, return a full explanation
/// of the issue
-const char *DiagnosticIDs::getFullExplanation(unsigned DiagID) {
+llvm::StringRef DiagnosticIDs::getFullExplanation(unsigned DiagID) {
if (const StaticDiagInfoRec *Info = GetDiagInfo(DiagID))
- return Info->FullExplanation;
- return 0;
+ return Info->getFullExplanation();
+ return llvm::StringRef();
}
/// getBuiltinDiagClass - Return the class field of the diagnostic.
@@ -264,10 +315,10 @@ namespace clang {
/// getDescription - Return the description of the specified custom
/// diagnostic.
- const char *getDescription(unsigned DiagID) const {
+ llvm::StringRef getDescription(unsigned DiagID) const {
assert(this && DiagID-DIAG_UPPER_LIMIT < DiagInfo.size() &&
"Invalid diagnosic ID");
- return DiagInfo[DiagID-DIAG_UPPER_LIMIT].second.c_str();
+ return DiagInfo[DiagID-DIAG_UPPER_LIMIT].second;
}
/// getLevel - Return the level of the specified custom diagnostic.
@@ -352,9 +403,9 @@ bool DiagnosticIDs::isBuiltinExtensionDiag(unsigned DiagID,
/// getDescription - Given a diagnostic ID, return a description of the
/// issue.
-const char *DiagnosticIDs::getDescription(unsigned DiagID) const {
+llvm::StringRef DiagnosticIDs::getDescription(unsigned DiagID) const {
if (const StaticDiagInfoRec *Info = GetDiagInfo(DiagID))
- return Info->Description;
+ return Info->getDescription();
return CustomDiagInfo->getDescription(DiagID);
}
@@ -493,9 +544,15 @@ DiagnosticIDs::getDiagnosticLevel(unsigned DiagID, unsigned DiagClass,
}
struct WarningOption {
- const char *Name;
+ // Be safe with the size of 'NameLen' because we don't statically check if the
+ // size will fit in the field; the struct size won't decrease with a shorter
+ // type anyway.
+ size_t NameLen;
+ const char *NameStr;
const short *Members;
const short *SubGroups;
+
+ llvm::StringRef getName() const { return llvm::StringRef(NameStr, NameLen); }
};
#define GET_DIAG_ARRAYS
@@ -513,7 +570,7 @@ sizeof(OptionTable) / sizeof(OptionTable[0]);
static bool WarningOptionCompare(const WarningOption &LHS,
const WarningOption &RHS) {
- return strcmp(LHS.Name, RHS.Name) < 0;
+ return LHS.getName() < RHS.getName();
}
static void MapGroupMembers(const WarningOption *Group, diag::Mapping Mapping,
@@ -534,10 +591,10 @@ static void MapGroupMembers(const WarningOption *Group, diag::Mapping Mapping,
/// setDiagnosticGroupMapping - Change an entire diagnostic group (e.g.
/// "unknown-pragmas" to have the specified mapping. This returns true and
/// ignores the request if "Group" was unknown, false otherwise.
-bool DiagnosticIDs::setDiagnosticGroupMapping(const char *Group,
- diag::Mapping Map,
- SourceLocation Loc,
- Diagnostic &Diag) const {
+bool DiagnosticIDs::setDiagnosticGroupMapping(llvm::StringRef Group,
+ diag::Mapping Map,
+ SourceLocation Loc,
+ Diagnostic &Diag) const {
assert((Loc.isValid() ||
Diag.DiagStatePoints.empty() ||
Diag.DiagStatePoints.back().Loc.isInvalid()) &&
@@ -548,12 +605,12 @@ bool DiagnosticIDs::setDiagnosticGroupMapping(const char *Group,
Diag.DiagStatePoints.back().Loc)) &&
"Source location of new mapping is before the previous one!");
- WarningOption Key = { Group, 0, 0 };
+ WarningOption Key = { Group.size(), Group.data(), 0, 0 };
const WarningOption *Found =
std::lower_bound(OptionTable, OptionTable + OptionTableSize, Key,
WarningOptionCompare);
if (Found == OptionTable + OptionTableSize ||
- strcmp(Found->Name, Group) != 0)
+ Found->getName() != Group)
return true; // Option not found.
MapGroupMembers(Found, Map, Loc, Diag);
diff --git a/lib/Basic/FileManager.cpp b/lib/Basic/FileManager.cpp
index 4e5a129..f747c53 100644
--- a/lib/Basic/FileManager.cpp
+++ b/lib/Basic/FileManager.cpp
@@ -264,10 +264,6 @@ void FileManager::addAncestorsAsVirtualDirs(llvm::StringRef Path) {
/// exist.
///
const DirectoryEntry *FileManager::getDirectory(llvm::StringRef DirName) {
- // stat doesn't like trailing separators (at least on Windows).
- if (DirName.size() > 1 && llvm::sys::path::is_separator(DirName.back()))
- DirName = DirName.substr(0, DirName.size()-1);
-
++NumDirLookups;
llvm::StringMapEntry<DirectoryEntry *> &NamedDirEnt =
SeenDirEntries.GetOrCreateValue(DirName);
diff --git a/lib/Basic/IdentifierTable.cpp b/lib/Basic/IdentifierTable.cpp
index cb1f55b..4711faa 100644
--- a/lib/Basic/IdentifierTable.cpp
+++ b/lib/Basic/IdentifierTable.cpp
@@ -392,6 +392,7 @@ ObjCMethodFamily Selector::getMethodFamilyImpl(Selector sel) {
if (name == "release") return OMF_release;
if (name == "retain") return OMF_retain;
if (name == "retainCount") return OMF_retainCount;
+ if (name == "self") return OMF_self;
}
// The other method families may begin with a prefix of underscores.
diff --git a/lib/Basic/SourceManager.cpp b/lib/Basic/SourceManager.cpp
index c3e0393..2de8ab7 100644
--- a/lib/Basic/SourceManager.cpp
+++ b/lib/Basic/SourceManager.cpp
@@ -961,6 +961,12 @@ static void ComputeLineNumbers(Diagnostic &Diag, ContentCache *FI,
/// about to emit a diagnostic.
unsigned SourceManager::getLineNumber(FileID FID, unsigned FilePos,
bool *Invalid) const {
+ if (FID.isInvalid()) {
+ if (Invalid)
+ *Invalid = true;
+ return 1;
+ }
+
ContentCache *Content;
if (LastLineNoFileIDQuery == FID)
Content = LastLineNoContentCache;
@@ -1207,6 +1213,73 @@ PresumedLoc SourceManager::getPresumedLoc(SourceLocation Loc) const {
return PresumedLoc(Filename, LineNo, ColNo, IncludeLoc);
}
+/// \brief Returns true if the given MacroID location points at the first
+/// token of the macro instantiation.
+bool SourceManager::isAtStartOfMacroInstantiation(SourceLocation loc) const {
+ assert(loc.isValid() && loc.isMacroID() && "Expected a valid macro loc");
+
+ unsigned FID = getFileID(loc).ID;
+ assert(FID > 1);
+ std::pair<SourceLocation, SourceLocation>
+ instRange = getImmediateInstantiationRange(loc);
+
+ bool invalid = false;
+ const SrcMgr::SLocEntry &Entry = getSLocEntry(FID-1, &invalid);
+ if (invalid)
+ return false;
+
+ // If the FileID immediately before it is a file then this is the first token
+ // in the macro.
+ if (Entry.isFile())
+ return true;
+
+ // If the FileID immediately before it (which is a macro token) is the
+ // immediate instantiated macro, check this macro token's location.
+ if (getFileID(instRange.second).ID == FID-1)
+ return isAtStartOfMacroInstantiation(instRange.first);
+
+ // If the FileID immediately before it (which is a macro token) came from a
+ // different instantiation, then this is the first token in the macro.
+ if (getInstantiationLoc(Entry.getInstantiation().getInstantiationLocStart())
+ != getInstantiationLoc(loc))
+ return true;
+
+ // It is inside the macro or the last token in the macro.
+ return false;
+}
+
+/// \brief Returns true if the given MacroID location points at the last
+/// token of the macro instantiation.
+bool SourceManager::isAtEndOfMacroInstantiation(SourceLocation loc) const {
+ assert(loc.isValid() && loc.isMacroID() && "Expected a valid macro loc");
+
+ unsigned FID = getFileID(loc).ID;
+ assert(FID > 1);
+ std::pair<SourceLocation, SourceLocation>
+ instRange = getInstantiationRange(loc);
+
+ // If there's no FileID after it, it is the last token in the macro.
+ if (FID+1 == sloc_entry_size())
+ return true;
+
+ bool invalid = false;
+ const SrcMgr::SLocEntry &Entry = getSLocEntry(FID+1, &invalid);
+ if (invalid)
+ return false;
+
+ // If the FileID immediately after it is a file or a macro token which
+ // came from a different instantiation, then this is the last token in the
+ // macro.
+ if (Entry.isFile())
+ return true;
+ if (getInstantiationLoc(Entry.getInstantiation().getInstantiationLocStart())
+ != instRange.first)
+ return true;
+
+ // It is inside the macro or the first token in the macro.
+ return false;
+}
+
//===----------------------------------------------------------------------===//
// Other miscellaneous methods.
//===----------------------------------------------------------------------===//
diff --git a/lib/Basic/Targets.cpp b/lib/Basic/Targets.cpp
index 97109ca..dd167dc 100644
--- a/lib/Basic/Targets.cpp
+++ b/lib/Basic/Targets.cpp
@@ -1121,7 +1121,7 @@ public:
}
virtual bool validateAsmConstraint(const char *&Name,
TargetInfo::ConstraintInfo &info) const;
- virtual std::string convertConstraint(const char Constraint) const;
+ virtual std::string convertConstraint(const char *&Constraint) const;
virtual const char *getClobbers() const {
return "~{dirflag},~{fpsr},~{flags}";
}
@@ -1180,7 +1180,7 @@ void X86TargetInfo::getDefaultFeatures(const std::string &CPU,
else if (CPU == "corei7") {
setFeatureEnabled(Features, "sse4", true);
setFeatureEnabled(Features, "aes", true);
- } else if (CPU == "sandybridge") {
+ } else if (CPU == "corei7-avx") {
setFeatureEnabled(Features, "sse4", true);
setFeatureEnabled(Features, "aes", true);
// setFeatureEnabled(Features, "avx", true);
@@ -1449,8 +1449,8 @@ X86TargetInfo::validateAsmConstraint(const char *&Name,
std::string
-X86TargetInfo::convertConstraint(const char Constraint) const {
- switch (Constraint) {
+X86TargetInfo::convertConstraint(const char *&Constraint) const {
+ switch (*Constraint) {
case 'a': return std::string("{ax}");
case 'b': return std::string("{bx}");
case 'c': return std::string("{cx}");
@@ -1464,7 +1464,7 @@ X86TargetInfo::convertConstraint(const char Constraint) const {
case 'u': // second from top of floating point stack.
return std::string("{st(1)}"); // second from top of floating point stack.
default:
- return std::string(1, Constraint);
+ return std::string(1, *Constraint);
}
}
} // end anonymous namespace
@@ -1993,11 +1993,11 @@ public:
if (CPU == "xscale")
Builder.defineMacro("__XSCALE__");
- bool IsThumb2 = IsThumb && (CPUArch == "6T2" || CPUArch.startswith("7"));
+ bool IsARMv7 = CPUArch.startswith("7");
if (IsThumb) {
Builder.defineMacro("__THUMBEL__");
Builder.defineMacro("__thumb__");
- if (IsThumb2)
+ if (CPUArch == "6T2" || IsARMv7)
Builder.defineMacro("__thumb2__");
}
@@ -2011,7 +2011,7 @@ public:
// the VFP define, hence the soft float and arch check. This is subtly
// different from gcc, we follow the intent which was that it should be set
// when Neon instructions are actually available.
- if (FPU == NeonFPU && !SoftFloat && IsThumb2)
+ if (FPU == NeonFPU && !SoftFloat && IsARMv7)
Builder.defineMacro("__ARM_NEON__");
}
virtual void getTargetBuiltins(const Builtin::Info *&Records,
@@ -2020,7 +2020,7 @@ public:
NumRecords = clang::ARM::LastTSBuiltin-Builtin::FirstTSBuiltin;
}
virtual const char *getVAListDeclaration() const {
- return "typedef char* __builtin_va_list;";
+ return "typedef void* __builtin_va_list;";
}
virtual void getGCCRegNames(const char * const *&Names,
unsigned &NumNames) const;
@@ -2037,9 +2037,31 @@ public:
case 'P': // VFP Floating point register double precision
Info.setAllowsRegister();
return true;
+ case 'U': // a memory reference...
+ switch (Name[1]) {
+ case 'q': // ...ARMV4 ldrsb
+ case 'v': // ...VFP load/store (reg+constant offset)
+ case 'y': // ...iWMMXt load/store
+ Info.setAllowsMemory();
+ Name++;
+ return true;
+ }
}
return false;
}
+ std::string
+ virtual convertConstraint(const char *&Constraint) const {
+ std::string R;
+ switch (*Constraint) {
+ case 'U': // Two-character constraint; add "^" hint for later parsing.
+ R = std::string("^") + std::string(Constraint, 2);
+ Constraint++;
+ break;
+ default:
+ return std::string(1, *Constraint);
+ }
+ return R;
+ }
virtual const char *getClobbers() const {
// FIXME: Is this really right?
return "";
@@ -2531,7 +2553,9 @@ class MipsTargetInfo : public TargetInfo {
public:
MipsTargetInfo(const std::string& triple) : TargetInfo(triple), ABI("o32") {
DescriptionString = "E-p:32:32:32-i1:8:8-i8:8:32-i16:16:32-i32:32:32-"
- "i64:32:64-f32:32:32-f64:64:64-v64:64:64-n32";
+ "i64:64:64-f32:32:32-f64:64:64-v64:64:64-n32";
+ SizeType = UnsignedInt;
+ PtrDiffType = SignedInt;
}
virtual const char *getABI() const { return ABI.c_str(); }
virtual bool setABI(const std::string &Name) {
@@ -2663,7 +2687,7 @@ class MipselTargetInfo : public MipsTargetInfo {
public:
MipselTargetInfo(const std::string& triple) : MipsTargetInfo(triple) {
DescriptionString = "e-p:32:32:32-i1:8:8-i8:8:32-i16:16:32-i32:32:32-"
- "i64:32:64-f32:32:32-f64:64:64-v64:64:64-n32";
+ "i64:64:64-f32:32:32-f64:64:64-v64:64:64-n32";
}
virtual void getTargetDefines(const LangOptions &Opts,
diff --git a/lib/CMakeLists.txt b/lib/CMakeLists.txt
index 0943e2b..b457434 100644
--- a/lib/CMakeLists.txt
+++ b/lib/CMakeLists.txt
@@ -13,4 +13,3 @@ add_subdirectory(Frontend)
add_subdirectory(FrontendTool)
add_subdirectory(Index)
add_subdirectory(StaticAnalyzer)
-add_subdirectory(Tooling)
diff --git a/lib/CodeGen/BackendUtil.cpp b/lib/CodeGen/BackendUtil.cpp
index 1264473..01d15ff 100644
--- a/lib/CodeGen/BackendUtil.cpp
+++ b/lib/CodeGen/BackendUtil.cpp
@@ -21,12 +21,11 @@
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/FormattedStream.h"
#include "llvm/Support/PrettyStackTrace.h"
-#include "llvm/Support/StandardPasses.h"
+#include "llvm/Support/PassManagerBuilder.h"
#include "llvm/Support/Timer.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/Target/SubtargetFeature.h"
#include "llvm/Target/TargetData.h"
-#include "llvm/Target/TargetLibraryInfo.h"
#include "llvm/Target/TargetMachine.h"
#include "llvm/Target/TargetOptions.h"
#include "llvm/Target/TargetRegistry.h"
@@ -109,67 +108,62 @@ void EmitAssemblyHelper::CreatePasses() {
OptLevel = 0;
Inlining = CodeGenOpts.NoInlining;
}
-
- FunctionPassManager *FPM = getPerFunctionPasses();
-
- TargetLibraryInfo *TLI =
- new TargetLibraryInfo(Triple(TheModule->getTargetTriple()));
+
+ PassManagerBuilder PMBuilder;
+ PMBuilder.OptLevel = OptLevel;
+ PMBuilder.SizeLevel = CodeGenOpts.OptimizeSize;
+
+ PMBuilder.DisableSimplifyLibCalls = !CodeGenOpts.SimplifyLibCalls;
+ PMBuilder.DisableUnitAtATime = !CodeGenOpts.UnitAtATime;
+ PMBuilder.DisableUnrollLoops = !CodeGenOpts.UnrollLoops;
+
+ // Figure out TargetLibraryInfo.
+ Triple TargetTriple(TheModule->getTargetTriple());
+ PMBuilder.LibraryInfo = new TargetLibraryInfo(TargetTriple);
if (!CodeGenOpts.SimplifyLibCalls)
- TLI->disableAllFunctions();
- FPM->add(TLI);
-
- // In -O0 if checking is disabled, we don't even have per-function passes.
- if (CodeGenOpts.VerifyModule)
- FPM->add(createVerifierPass());
-
- // Assume that standard function passes aren't run for -O0.
- if (OptLevel > 0)
- llvm::createStandardFunctionPasses(FPM, OptLevel);
-
- llvm::Pass *InliningPass = 0;
+ PMBuilder.LibraryInfo->disableAllFunctions();
+
switch (Inlining) {
case CodeGenOptions::NoInlining: break;
case CodeGenOptions::NormalInlining: {
- // Set the inline threshold following llvm-gcc.
- //
// FIXME: Derive these constants in a principled fashion.
unsigned Threshold = 225;
- if (CodeGenOpts.OptimizeSize == 1) //-Os
+ if (CodeGenOpts.OptimizeSize == 1) // -Os
Threshold = 75;
- else if (CodeGenOpts.OptimizeSize == 2) //-Oz
+ else if (CodeGenOpts.OptimizeSize == 2) // -Oz
Threshold = 25;
else if (OptLevel > 2)
Threshold = 275;
- InliningPass = createFunctionInliningPass(Threshold);
+ PMBuilder.Inliner = createFunctionInliningPass(Threshold);
break;
}
case CodeGenOptions::OnlyAlwaysInlining:
- InliningPass = createAlwaysInlinerPass(); // Respect always_inline
+ // Respect always_inline.
+ PMBuilder.Inliner = createAlwaysInlinerPass();
break;
}
- PassManager *MPM = getPerModulePasses();
+
+ // Set up the per-function pass manager.
+ FunctionPassManager *FPM = getPerFunctionPasses();
+ if (CodeGenOpts.VerifyModule)
+ FPM->add(createVerifierPass());
+ PMBuilder.populateFunctionPassManager(*FPM);
- TLI = new TargetLibraryInfo(Triple(TheModule->getTargetTriple()));
- if (!CodeGenOpts.SimplifyLibCalls)
- TLI->disableAllFunctions();
- MPM->add(TLI);
+ // Set up the per-module pass manager.
+ PassManager *MPM = getPerModulePasses();
if (CodeGenOpts.EmitGcovArcs || CodeGenOpts.EmitGcovNotes) {
MPM->add(createGCOVProfilerPass(CodeGenOpts.EmitGcovNotes,
- CodeGenOpts.EmitGcovArcs));
+ CodeGenOpts.EmitGcovArcs,
+ TargetTriple.isMacOSX()));
+
if (!CodeGenOpts.DebugInfo)
MPM->add(createStripSymbolsPass(true));
}
-
- // For now we always create per module passes.
- llvm::createStandardModulePasses(MPM, OptLevel,
- CodeGenOpts.OptimizeSize,
- CodeGenOpts.UnitAtATime,
- CodeGenOpts.UnrollLoops,
- CodeGenOpts.SimplifyLibCalls,
- /*HaveExceptions=*/true,
- InliningPass);
+
+
+ PMBuilder.populateModulePassManager(*MPM);
}
bool EmitAssemblyHelper::AddEmitPasses(BackendAction Action,
@@ -215,7 +209,6 @@ bool EmitAssemblyHelper::AddEmitPasses(BackendAction Action,
NoZerosInBSS = CodeGenOpts.NoZeroInitializedInBSS;
llvm::UnsafeFPMath = CodeGenOpts.UnsafeFPMath;
llvm::UseSoftFloat = CodeGenOpts.SoftFloat;
- UnwindTablesMandatory = CodeGenOpts.UnwindTables;
TargetMachine::setAsmVerbosityDefault(CodeGenOpts.AsmVerbose);
diff --git a/lib/CodeGen/CGBlocks.cpp b/lib/CodeGen/CGBlocks.cpp
index 99a69a4..e5da703 100644
--- a/lib/CodeGen/CGBlocks.cpp
+++ b/lib/CodeGen/CGBlocks.cpp
@@ -189,23 +189,6 @@ namespace {
}
}
-/// Determines if the given record type has a mutable field.
-static bool hasMutableField(const CXXRecordDecl *record) {
- for (CXXRecordDecl::field_iterator
- i = record->field_begin(), e = record->field_end(); i != e; ++i)
- if ((*i)->isMutable())
- return true;
-
- for (CXXRecordDecl::base_class_const_iterator
- i = record->bases_begin(), e = record->bases_end(); i != e; ++i) {
- const RecordType *record = i->getType()->castAs<RecordType>();
- if (hasMutableField(cast<CXXRecordDecl>(record->getDecl())))
- return true;
- }
-
- return false;
-}
-
/// Determines if the given type is safe for constant capture in C++.
static bool isSafeForCXXConstantCapture(QualType type) {
const RecordType *recordType =
@@ -222,7 +205,7 @@ static bool isSafeForCXXConstantCapture(QualType type) {
// Otherwise, we just have to make sure there aren't any mutable
// fields that might have changed since initialization.
- return !hasMutableField(record);
+ return !record->hasMutableFields();
}
/// It is illegal to modify a const object after initialization.
@@ -262,7 +245,7 @@ static CharUnits getLowBit(CharUnits v) {
}
static void initializeForBlockHeader(CodeGenModule &CGM, CGBlockInfo &info,
- std::vector<const llvm::Type*> &elementTypes) {
+ llvm::SmallVectorImpl<const llvm::Type*> &elementTypes) {
ASTContext &C = CGM.getContext();
// The header is basically a 'struct { void *; int; int; void *; void *; }'.
@@ -299,7 +282,7 @@ static void computeBlockInfo(CodeGenModule &CGM, CGBlockInfo &info) {
ASTContext &C = CGM.getContext();
const BlockDecl *block = info.getBlockDecl();
- std::vector<const llvm::Type*> elementTypes;
+ llvm::SmallVector<const llvm::Type*, 8> elementTypes;
initializeForBlockHeader(CGM, info, elementTypes);
if (!block->hasCaptures()) {
@@ -321,7 +304,11 @@ static void computeBlockInfo(CodeGenModule &CGM, CGBlockInfo &info) {
const DeclContext *DC = block->getDeclContext();
for (; isa<BlockDecl>(DC); DC = cast<BlockDecl>(DC)->getDeclContext())
;
- QualType thisType = cast<CXXMethodDecl>(DC)->getThisType(C);
+ QualType thisType;
+ if (const CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(DC))
+ thisType = C.getPointerType(C.getRecordType(RD));
+ else
+ thisType = cast<CXXMethodDecl>(DC)->getThisType(C);
const llvm::Type *llvmType = CGM.getTypes().ConvertType(thisType);
std::pair<CharUnits,CharUnits> tinfo
@@ -720,9 +707,8 @@ RValue CodeGenFunction::EmitBlockCallExpr(const CallExpr* E,
BlockLiteral = Builder.CreateBitCast(BlockLiteral, VoidPtrTy, "tmp");
// Add the block literal.
- QualType VoidPtrTy = getContext().getPointerType(getContext().VoidTy);
CallArgList Args;
- Args.add(RValue::get(BlockLiteral), VoidPtrTy);
+ Args.add(RValue::get(BlockLiteral), getContext().VoidPtrTy);
QualType FnType = BPT->getPointeeType();
@@ -1063,6 +1049,10 @@ CodeGenFunction::GenerateCopyHelperFunction(const CGBlockInfo &blockInfo) {
IdentifierInfo *II
= &CGM.getContext().Idents.get("__copy_helper_block_");
+ // Check if we should generate debug info for this block helper function.
+ if (CGM.getModuleDebugInfo())
+ DebugInfo = CGM.getModuleDebugInfo();
+
FunctionDecl *FD = FunctionDecl::Create(C,
C.getTranslationUnitDecl(),
SourceLocation(),
@@ -1150,6 +1140,10 @@ CodeGenFunction::GenerateDestroyHelperFunction(const CGBlockInfo &blockInfo) {
llvm::Function::Create(LTy, llvm::GlobalValue::InternalLinkage,
"__destroy_helper_block_", &CGM.getModule());
+ // Check if we should generate debug info for this block destroy function.
+ if (CGM.getModuleDebugInfo())
+ DebugInfo = CGM.getModuleDebugInfo();
+
IdentifierInfo *II
= &CGM.getContext().Idents.get("__destroy_helper_block_");
@@ -1508,29 +1502,29 @@ const llvm::Type *CodeGenFunction::BuildByRefType(const VarDecl *D) {
QualType Ty = D->getType();
- std::vector<const llvm::Type *> Types;
+ llvm::SmallVector<const llvm::Type *, 8> types;
llvm::PATypeHolder ByRefTypeHolder = llvm::OpaqueType::get(getLLVMContext());
// void *__isa;
- Types.push_back(Int8PtrTy);
+ types.push_back(Int8PtrTy);
// void *__forwarding;
- Types.push_back(llvm::PointerType::getUnqual(ByRefTypeHolder));
+ types.push_back(llvm::PointerType::getUnqual(ByRefTypeHolder));
// int32_t __flags;
- Types.push_back(Int32Ty);
+ types.push_back(Int32Ty);
// int32_t __size;
- Types.push_back(Int32Ty);
+ types.push_back(Int32Ty);
bool HasCopyAndDispose = getContext().BlockRequiresCopying(Ty);
if (HasCopyAndDispose) {
/// void *__copy_helper;
- Types.push_back(Int8PtrTy);
+ types.push_back(Int8PtrTy);
/// void *__destroy_helper;
- Types.push_back(Int8PtrTy);
+ types.push_back(Int8PtrTy);
}
bool Packed = false;
@@ -1553,11 +1547,11 @@ const llvm::Type *CodeGenFunction::BuildByRefType(const VarDecl *D) {
if (NumPaddingBytes > 0) {
const llvm::Type *Ty = llvm::Type::getInt8Ty(getLLVMContext());
// FIXME: We need a sema error for alignment larger than the minimum of
- // the maximal stack alignmint and the alignment of malloc on the system.
+ // the maximal stack alignment and the alignment of malloc on the system.
if (NumPaddingBytes > 1)
Ty = llvm::ArrayType::get(Ty, NumPaddingBytes);
- Types.push_back(Ty);
+ types.push_back(Ty);
// We want a packed struct.
Packed = true;
@@ -1565,9 +1559,9 @@ const llvm::Type *CodeGenFunction::BuildByRefType(const VarDecl *D) {
}
// T x;
- Types.push_back(ConvertTypeForMem(Ty));
+ types.push_back(ConvertTypeForMem(Ty));
- const llvm::Type *T = llvm::StructType::get(getLLVMContext(), Types, Packed);
+ const llvm::Type *T = llvm::StructType::get(getLLVMContext(), types, Packed);
cast<llvm::OpaqueType>(ByRefTypeHolder.get())->refineAbstractTypeTo(T);
CGM.getModule().addTypeName("struct.__block_byref_" + D->getNameAsString(),
@@ -1575,7 +1569,7 @@ const llvm::Type *CodeGenFunction::BuildByRefType(const VarDecl *D) {
Info.first = ByRefTypeHolder.get();
- Info.second = Types.size() - 1;
+ Info.second = types.size() - 1;
return Info.first;
}
diff --git a/lib/CodeGen/CGBuiltin.cpp b/lib/CodeGen/CGBuiltin.cpp
index 7a0c8da..14bebaf 100644
--- a/lib/CodeGen/CGBuiltin.cpp
+++ b/lib/CodeGen/CGBuiltin.cpp
@@ -164,9 +164,8 @@ static Value *EmitFAbs(CodeGenFunction &CGF, Value *V, QualType ValTy) {
}
// 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::FunctionType *FT = llvm::FunctionType::get(V->getType(), V->getType(),
+ false);
llvm::Value *Fn = CGF.CGM.CreateRuntimeFunction(FT, FnName);
return CGF.Builder.CreateCall(Fn, V, "abs");
@@ -1186,6 +1185,41 @@ Value *CodeGenFunction::EmitARMBuiltinExpr(unsigned BuiltinID,
Ops.begin(), Ops.end());
}
+ if (BuiltinID == ARM::BI__builtin_arm_ldrexd) {
+ Function *F = CGM.getIntrinsic(Intrinsic::arm_ldrexd);
+
+ Value *LdPtr = EmitScalarExpr(E->getArg(0));
+ Value *Val = Builder.CreateCall(F, LdPtr, "ldrexd");
+
+ Value *Val0 = Builder.CreateExtractValue(Val, 1);
+ Value *Val1 = Builder.CreateExtractValue(Val, 0);
+ Val0 = Builder.CreateZExt(Val0, Int64Ty);
+ Val1 = Builder.CreateZExt(Val1, Int64Ty);
+
+ Value *ShiftCst = llvm::ConstantInt::get(Int64Ty, 32);
+ Val = Builder.CreateShl(Val0, ShiftCst, "shl", true /* nuw */);
+ return Builder.CreateOr(Val, Val1);
+ }
+
+ if (BuiltinID == ARM::BI__builtin_arm_strexd) {
+ Function *F = CGM.getIntrinsic(Intrinsic::arm_strexd);
+ llvm::Type *STy = llvm::StructType::get(getLLVMContext(), Int32Ty, Int32Ty,
+ NULL);
+
+ Value *One = llvm::ConstantInt::get(Int32Ty, 1);
+ Value *Tmp = Builder.CreateAlloca(Int64Ty, One, "tmp");
+ Value *Val = EmitScalarExpr(E->getArg(0));
+ Builder.CreateStore(Val, Tmp);
+
+ Value *LdPtr = Builder.CreateBitCast(Tmp,llvm::PointerType::getUnqual(STy));
+ Val = Builder.CreateLoad(LdPtr);
+
+ Value *Arg0 = Builder.CreateExtractValue(Val, 0);
+ Value *Arg1 = Builder.CreateExtractValue(Val, 1);
+ Value *StPtr = EmitScalarExpr(E->getArg(1));
+ return Builder.CreateCall3(F, Arg0, Arg1, StPtr, "strexd");
+ }
+
llvm::SmallVector<Value*, 4> Ops;
for (unsigned i = 0, e = E->getNumArgs() - 1; i != e; i++)
Ops.push_back(EmitScalarExpr(E->getArg(i)));
@@ -2143,16 +2177,21 @@ Value *CodeGenFunction::EmitX86BuiltinExpr(unsigned BuiltinID,
// If palignr is shifting the pair of vectors more than 32 bytes, emit zero.
return llvm::Constant::getNullValue(ConvertType(E->getType()));
}
- case X86::BI__builtin_ia32_loaddqu: {
- const llvm::Type *VecTy = ConvertType(E->getType());
- const llvm::Type *IntTy = llvm::IntegerType::get(getLLVMContext(), 128);
+ case X86::BI__builtin_ia32_movntps:
+ case X86::BI__builtin_ia32_movntpd:
+ case X86::BI__builtin_ia32_movntdq:
+ case X86::BI__builtin_ia32_movnti: {
+ llvm::MDNode *Node = llvm::MDNode::get(getLLVMContext(),
+ Builder.getInt32(1));
+ // Convert the type of the pointer to a pointer to the stored type.
Value *BC = Builder.CreateBitCast(Ops[0],
- llvm::PointerType::getUnqual(IntTy),
+ llvm::PointerType::getUnqual(Ops[1]->getType()),
"cast");
- LoadInst *LI = Builder.CreateLoad(BC);
- LI->setAlignment(1); // Unaligned load.
- return Builder.CreateBitCast(LI, VecTy, "loadu.cast");
+ StoreInst *SI = Builder.CreateStore(Ops[1], BC);
+ SI->setMetadata(CGM.getModule().getMDKindID("nontemporal"), Node);
+ SI->setAlignment(16);
+ return SI;
}
// 3DNow!
case X86::BI__builtin_ia32_pavgusb:
diff --git a/lib/CodeGen/CGCXX.cpp b/lib/CodeGen/CGCXX.cpp
index 184147c..f6fc202 100644
--- a/lib/CodeGen/CGCXX.cpp
+++ b/lib/CodeGen/CGCXX.cpp
@@ -28,17 +28,6 @@
using namespace clang;
using namespace CodeGen;
-/// Determines whether the given function has a trivial body that does
-/// not require any specific codegen.
-static bool HasTrivialBody(const FunctionDecl *FD) {
- Stmt *S = FD->getBody();
- if (!S)
- return true;
- if (isa<CompoundStmt>(S) && cast<CompoundStmt>(S)->body_empty())
- return true;
- return false;
-}
-
/// Try to emit a base destructor as an alias to its primary
/// base-class destructor.
bool CodeGenModule::TryEmitBaseDestructorAsAlias(const CXXDestructorDecl *D) {
@@ -47,7 +36,7 @@ bool CodeGenModule::TryEmitBaseDestructorAsAlias(const CXXDestructorDecl *D) {
// If the destructor doesn't have a trivial body, we have to emit it
// separately.
- if (!HasTrivialBody(D))
+ if (!D->hasTrivialBody())
return true;
const CXXRecordDecl *Class = D->getParent();
@@ -187,7 +176,10 @@ bool CodeGenModule::TryEmitDefinitionAsAlias(GlobalDecl AliasDecl,
void CodeGenModule::EmitCXXConstructors(const CXXConstructorDecl *D) {
// The constructor used for constructing this as a complete class;
// constucts the virtual bases, then calls the base constructor.
- EmitGlobal(GlobalDecl(D, Ctor_Complete));
+ if (!D->getParent()->isAbstract()) {
+ // We don't need to emit the complete ctor if the class is abstract.
+ EmitGlobal(GlobalDecl(D, Ctor_Complete));
+ }
// The constructor used for constructing this as a base class;
// ignores virtual bases.
@@ -244,7 +236,11 @@ void CodeGenModule::EmitCXXDestructors(const CXXDestructorDecl *D) {
// The destructor used for destructing this as a most-derived class;
// call the base destructor and then destructs any virtual bases.
- EmitGlobal(GlobalDecl(D, Dtor_Complete));
+ if (!D->getParent()->isAbstract() || D->isVirtual()) {
+ // We don't need to emit the complete ctor if the class is abstract,
+ // unless the destructor is virtual and needs to be in the vtable.
+ EmitGlobal(GlobalDecl(D, Dtor_Complete));
+ }
// The destructor used for destructing this as a base class; ignores
// virtual bases.
diff --git a/lib/CodeGen/CGCall.cpp b/lib/CodeGen/CGCall.cpp
index a765f0f..712ae89 100644
--- a/lib/CodeGen/CGCall.cpp
+++ b/lib/CodeGen/CGCall.cpp
@@ -309,10 +309,10 @@ CGFunctionInfo::CGFunctionInfo(unsigned _CallingConvention,
/***/
-void CodeGenTypes::GetExpandedTypes(QualType Ty,
- std::vector<const llvm::Type*> &ArgTys,
- bool IsRecursive) {
- const RecordType *RT = Ty->getAsStructureType();
+void CodeGenTypes::GetExpandedTypes(QualType type,
+ llvm::SmallVectorImpl<const llvm::Type*> &expandedTypes,
+ bool isRecursive) {
+ const RecordType *RT = type->getAsStructureType();
assert(RT && "Can only expand structure types.");
const RecordDecl *RD = RT->getDecl();
assert(!RD->hasFlexibleArrayMember() &&
@@ -324,11 +324,11 @@ void CodeGenTypes::GetExpandedTypes(QualType Ty,
assert(!FD->isBitField() &&
"Cannot expand structure with bit-field members.");
- QualType FT = FD->getType();
- if (CodeGenFunction::hasAggregateLLVMType(FT))
- GetExpandedTypes(FT, ArgTys, IsRecursive);
+ QualType fieldType = FD->getType();
+ if (fieldType->isRecordType())
+ GetExpandedTypes(fieldType, expandedTypes, isRecursive);
else
- ArgTys.push_back(ConvertType(FT, IsRecursive));
+ expandedTypes.push_back(ConvertType(fieldType, isRecursive));
}
}
@@ -513,6 +513,29 @@ static llvm::Value *CreateCoercedLoad(llvm::Value *SrcPtr,
return CGF.Builder.CreateLoad(Tmp);
}
+// Function to store a first-class aggregate into memory. We prefer to
+// store the elements rather than the aggregate to be more friendly to
+// fast-isel.
+// FIXME: Do we need to recurse here?
+static void BuildAggStore(CodeGenFunction &CGF, llvm::Value *Val,
+ llvm::Value *DestPtr, bool DestIsVolatile,
+ bool LowAlignment) {
+ // Prefer scalar stores to first-class aggregate stores.
+ if (const llvm::StructType *STy =
+ dyn_cast<llvm::StructType>(Val->getType())) {
+ for (unsigned i = 0, e = STy->getNumElements(); i != e; ++i) {
+ llvm::Value *EltPtr = CGF.Builder.CreateConstGEP2_32(DestPtr, 0, i);
+ llvm::Value *Elt = CGF.Builder.CreateExtractValue(Val, i);
+ llvm::StoreInst *SI = CGF.Builder.CreateStore(Elt, EltPtr,
+ DestIsVolatile);
+ if (LowAlignment)
+ SI->setAlignment(1);
+ }
+ } else {
+ CGF.Builder.CreateStore(Val, DestPtr, DestIsVolatile);
+ }
+}
+
/// CreateCoercedStore - Create a store to \arg DstPtr from \arg Src,
/// where the source and destination may have different types.
///
@@ -553,7 +576,7 @@ static void CreateCoercedStore(llvm::Value *Src,
llvm::Value *Casted =
CGF.Builder.CreateBitCast(DstPtr, llvm::PointerType::getUnqual(SrcTy));
// FIXME: Use better alignment / avoid requiring aligned store.
- CGF.Builder.CreateStore(Src, Casted, DstIsVolatile)->setAlignment(1);
+ BuildAggStore(CGF, Src, Casted, DstIsVolatile, true);
} else {
// Otherwise do coercion through memory. This is stupid, but
// simple.
@@ -612,49 +635,49 @@ const llvm::FunctionType *CodeGenTypes::GetFunctionType(GlobalDecl GD) {
}
const llvm::FunctionType *
-CodeGenTypes::GetFunctionType(const CGFunctionInfo &FI, bool IsVariadic,
- bool IsRecursive) {
- std::vector<const llvm::Type*> ArgTys;
+CodeGenTypes::GetFunctionType(const CGFunctionInfo &FI, bool isVariadic,
+ bool isRecursive) {
+ llvm::SmallVector<const llvm::Type*, 8> argTypes;
+ const llvm::Type *resultType = 0;
- const llvm::Type *ResultType = 0;
-
- QualType RetTy = FI.getReturnType();
- const ABIArgInfo &RetAI = FI.getReturnInfo();
- switch (RetAI.getKind()) {
+ const ABIArgInfo &retAI = FI.getReturnInfo();
+ switch (retAI.getKind()) {
case ABIArgInfo::Expand:
- assert(0 && "Invalid ABI kind for return argument");
+ llvm_unreachable("Invalid ABI kind for return argument");
case ABIArgInfo::Extend:
case ABIArgInfo::Direct:
- ResultType = RetAI.getCoerceToType();
+ resultType = retAI.getCoerceToType();
break;
case ABIArgInfo::Indirect: {
- assert(!RetAI.getIndirectAlign() && "Align unused on indirect return.");
- ResultType = llvm::Type::getVoidTy(getLLVMContext());
- const llvm::Type *STy = ConvertType(RetTy, IsRecursive);
- unsigned AS = Context.getTargetAddressSpace(RetTy);
- ArgTys.push_back(llvm::PointerType::get(STy, AS));
+ assert(!retAI.getIndirectAlign() && "Align unused on indirect return.");
+ resultType = llvm::Type::getVoidTy(getLLVMContext());
+
+ QualType ret = FI.getReturnType();
+ const llvm::Type *ty = ConvertType(ret, isRecursive);
+ unsigned addressSpace = Context.getTargetAddressSpace(ret);
+ argTypes.push_back(llvm::PointerType::get(ty, addressSpace));
break;
}
case ABIArgInfo::Ignore:
- ResultType = llvm::Type::getVoidTy(getLLVMContext());
+ resultType = llvm::Type::getVoidTy(getLLVMContext());
break;
}
for (CGFunctionInfo::const_arg_iterator it = FI.arg_begin(),
ie = FI.arg_end(); it != ie; ++it) {
- const ABIArgInfo &AI = it->info;
+ const ABIArgInfo &argAI = it->info;
- switch (AI.getKind()) {
+ switch (argAI.getKind()) {
case ABIArgInfo::Ignore:
break;
case ABIArgInfo::Indirect: {
// indirect arguments are always on the stack, which is addr space #0.
- const llvm::Type *LTy = ConvertTypeForMem(it->type, IsRecursive);
- ArgTys.push_back(llvm::PointerType::getUnqual(LTy));
+ const llvm::Type *LTy = ConvertTypeForMem(it->type, isRecursive);
+ argTypes.push_back(LTy->getPointerTo());
break;
}
@@ -663,23 +686,23 @@ CodeGenTypes::GetFunctionType(const CGFunctionInfo &FI, bool IsVariadic,
// If the coerce-to type is a first class aggregate, flatten it. Either
// way is semantically identical, but fast-isel and the optimizer
// generally likes scalar values better than FCAs.
- const llvm::Type *ArgTy = AI.getCoerceToType();
- if (const llvm::StructType *STy = dyn_cast<llvm::StructType>(ArgTy)) {
- for (unsigned i = 0, e = STy->getNumElements(); i != e; ++i)
- ArgTys.push_back(STy->getElementType(i));
+ const llvm::Type *argType = argAI.getCoerceToType();
+ if (const llvm::StructType *st = dyn_cast<llvm::StructType>(argType)) {
+ for (unsigned i = 0, e = st->getNumElements(); i != e; ++i)
+ argTypes.push_back(st->getElementType(i));
} else {
- ArgTys.push_back(ArgTy);
+ argTypes.push_back(argType);
}
break;
}
case ABIArgInfo::Expand:
- GetExpandedTypes(it->type, ArgTys, IsRecursive);
+ GetExpandedTypes(it->type, argTypes, isRecursive);
break;
}
}
- return llvm::FunctionType::get(ResultType, ArgTys, IsVariadic);
+ return llvm::FunctionType::get(resultType, argTypes, isVariadic);
}
const llvm::Type *CodeGenTypes::GetFunctionTypeForVTable(GlobalDecl GD) {
@@ -786,9 +809,9 @@ void CodeGenModule::ConstructAttributeList(const CGFunctionInfo &FI,
// sense to do it here because parameters are so messed up.
switch (AI.getKind()) {
case ABIArgInfo::Extend:
- if (ParamType->isSignedIntegerType())
+ if (ParamType->isSignedIntegerOrEnumerationType())
Attributes |= llvm::Attribute::SExt;
- else if (ParamType->isUnsignedIntegerType())
+ else if (ParamType->isUnsignedIntegerOrEnumerationType())
Attributes |= llvm::Attribute::ZExt;
// FALL THROUGH
case ABIArgInfo::Direct:
@@ -822,12 +845,12 @@ void CodeGenModule::ConstructAttributeList(const CGFunctionInfo &FI,
continue;
case ABIArgInfo::Expand: {
- std::vector<const llvm::Type*> Tys;
+ llvm::SmallVector<const llvm::Type*, 8> types;
// FIXME: This is rather inefficient. Do we ever actually need to do
// anything here? The result should be just reconstructed on the other
// side, so extension should be a non-issue.
- getTypes().GetExpandedTypes(ParamType, Tys, false);
- Index += Tys.size();
+ getTypes().GetExpandedTypes(ParamType, types, false);
+ Index += types.size();
continue;
}
}
@@ -1166,6 +1189,15 @@ void CodeGenFunction::EmitCallArg(CallArgList &args, const Expr *E,
return args.add(EmitReferenceBindingToExpr(E, /*InitializedDecl=*/0),
type);
+ if (hasAggregateLLVMType(type) && isa<ImplicitCastExpr>(E) &&
+ cast<CastExpr>(E)->getCastKind() == CK_LValueToRValue) {
+ LValue L = EmitLValue(cast<CastExpr>(E)->getSubExpr());
+ assert(L.isSimple());
+ args.add(RValue::getAggregate(L.getAddress(), L.isVolatileQualified()),
+ type, /*NeedsCopy*/true);
+ return;
+ }
+
args.add(EmitAnyExprToTemp(E), type);
}
@@ -1231,6 +1263,10 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo,
Alignment, I->Ty);
else
StoreComplexToAddr(RV.getComplexVal(), Args.back(), false);
+ } else if (I->NeedsCopy && !ArgInfo.getIndirectByVal()) {
+ Args.push_back(CreateMemTemp(I->Ty));
+ EmitAggregateCopy(Args.back(), RV.getAggregateAddr(), I->Ty,
+ RV.isVolatileQualified());
} else {
Args.push_back(RV.getAggregateAddr());
}
@@ -1409,7 +1445,7 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo,
DestPtr = CreateMemTemp(RetTy, "agg.tmp");
DestIsVolatile = false;
}
- Builder.CreateStore(CI, DestPtr, DestIsVolatile);
+ BuildAggStore(*this, CI, DestPtr, DestIsVolatile, false);
return RValue::getAggregate(DestPtr);
}
return RValue::get(CI);
diff --git a/lib/CodeGen/CGCall.h b/lib/CodeGen/CGCall.h
index 3f600c0..160a62e 100644
--- a/lib/CodeGen/CGCall.h
+++ b/lib/CodeGen/CGCall.h
@@ -47,8 +47,9 @@ namespace CodeGen {
struct CallArg {
RValue RV;
QualType Ty;
- CallArg(RValue rv, QualType ty)
- : RV(rv), Ty(ty)
+ bool NeedsCopy;
+ CallArg(RValue rv, QualType ty, bool needscopy)
+ : RV(rv), Ty(ty), NeedsCopy(needscopy)
{ }
};
@@ -57,8 +58,8 @@ namespace CodeGen {
class CallArgList :
public llvm::SmallVector<CallArg, 16> {
public:
- void add(RValue rvalue, QualType type) {
- push_back(CallArg(rvalue, type));
+ void add(RValue rvalue, QualType type, bool needscopy = false) {
+ push_back(CallArg(rvalue, type, needscopy));
}
};
diff --git a/lib/CodeGen/CGClass.cpp b/lib/CodeGen/CGClass.cpp
index ca8b657..5725d80 100644
--- a/lib/CodeGen/CGClass.cpp
+++ b/lib/CodeGen/CGClass.cpp
@@ -520,6 +520,7 @@ static void EmitMemberInitializer(CodeGenFunction &CGF,
FunctionArgList &Args) {
assert(MemberInit->isAnyMemberInitializer() &&
"Must have member initializer!");
+ assert(MemberInit->getInit() && "Must have initializer!");
// non-static data member initializers.
FieldDecl *Field = MemberInit->getAnyMember();
@@ -726,12 +727,13 @@ void CodeGenFunction::EmitCtorPrologue(const CXXConstructorDecl *CD,
B != E; ++B) {
CXXCtorInitializer *Member = (*B);
- if (Member->isBaseInitializer())
+ if (Member->isBaseInitializer()) {
EmitBaseInitializer(*this, ClassDecl, Member, CtorType);
- else if (Member->isAnyMemberInitializer())
+ } else {
+ assert(Member->isAnyMemberInitializer() &&
+ "Delegating initializer on non-delegating constructor");
MemberInitializers.push_back(Member);
- else
- llvm_unreachable("Delegating initializer on non-delegating constructor");
+ }
}
InitializeVTablePointers(ClassDecl);
@@ -740,6 +742,94 @@ void CodeGenFunction::EmitCtorPrologue(const CXXConstructorDecl *CD,
EmitMemberInitializer(*this, ClassDecl, MemberInitializers[I], CD, Args);
}
+static bool
+FieldHasTrivialDestructorBody(ASTContext &Context, const FieldDecl *Field);
+
+static bool
+HasTrivialDestructorBody(ASTContext &Context,
+ const CXXRecordDecl *BaseClassDecl,
+ const CXXRecordDecl *MostDerivedClassDecl)
+{
+ // If the destructor is trivial we don't have to check anything else.
+ if (BaseClassDecl->hasTrivialDestructor())
+ return true;
+
+ if (!BaseClassDecl->getDestructor()->hasTrivialBody())
+ return false;
+
+ // Check fields.
+ for (CXXRecordDecl::field_iterator I = BaseClassDecl->field_begin(),
+ E = BaseClassDecl->field_end(); I != E; ++I) {
+ const FieldDecl *Field = *I;
+
+ if (!FieldHasTrivialDestructorBody(Context, Field))
+ return false;
+ }
+
+ // Check non-virtual bases.
+ for (CXXRecordDecl::base_class_const_iterator I =
+ BaseClassDecl->bases_begin(), E = BaseClassDecl->bases_end();
+ I != E; ++I) {
+ if (I->isVirtual())
+ continue;
+
+ const CXXRecordDecl *NonVirtualBase =
+ cast<CXXRecordDecl>(I->getType()->castAs<RecordType>()->getDecl());
+ if (!HasTrivialDestructorBody(Context, NonVirtualBase,
+ MostDerivedClassDecl))
+ return false;
+ }
+
+ if (BaseClassDecl == MostDerivedClassDecl) {
+ // Check virtual bases.
+ for (CXXRecordDecl::base_class_const_iterator I =
+ BaseClassDecl->vbases_begin(), E = BaseClassDecl->vbases_end();
+ I != E; ++I) {
+ const CXXRecordDecl *VirtualBase =
+ cast<CXXRecordDecl>(I->getType()->castAs<RecordType>()->getDecl());
+ if (!HasTrivialDestructorBody(Context, VirtualBase,
+ MostDerivedClassDecl))
+ return false;
+ }
+ }
+
+ return true;
+}
+
+static bool
+FieldHasTrivialDestructorBody(ASTContext &Context,
+ const FieldDecl *Field)
+{
+ QualType FieldBaseElementType = Context.getBaseElementType(Field->getType());
+
+ const RecordType *RT = FieldBaseElementType->getAs<RecordType>();
+ if (!RT)
+ return true;
+
+ CXXRecordDecl *FieldClassDecl = cast<CXXRecordDecl>(RT->getDecl());
+ return HasTrivialDestructorBody(Context, FieldClassDecl, FieldClassDecl);
+}
+
+/// CanSkipVTablePointerInitialization - Check whether we need to initialize
+/// any vtable pointers before calling this destructor.
+static bool CanSkipVTablePointerInitialization(ASTContext &Context,
+ const CXXDestructorDecl *Dtor) {
+ if (!Dtor->hasTrivialBody())
+ return false;
+
+ // Check the fields.
+ const CXXRecordDecl *ClassDecl = Dtor->getParent();
+ for (CXXRecordDecl::field_iterator I = ClassDecl->field_begin(),
+ E = ClassDecl->field_end(); I != E; ++I) {
+ const FieldDecl *Field = *I;
+
+ if (!FieldHasTrivialDestructorBody(Context, Field))
+ return false;
+ }
+
+ return true;
+}
+
/// EmitDestructorBody - Emits the body of the current destructor.
void CodeGenFunction::EmitDestructorBody(FunctionArgList &Args) {
const CXXDestructorDecl *Dtor = cast<CXXDestructorDecl>(CurGD.getDecl());
@@ -791,7 +881,8 @@ void CodeGenFunction::EmitDestructorBody(FunctionArgList &Args) {
EnterDtorCleanups(Dtor, Dtor_Base);
// Initialize the vtable pointers before entering the body.
- InitializeVTablePointers(Dtor->getParent());
+ if (!CanSkipVTablePointerInitialization(getContext(), Dtor))
+ InitializeVTablePointers(Dtor->getParent());
if (isTryBody)
EmitStmt(cast<CXXTryStmt>(Body)->getTryBlock());
@@ -1269,6 +1360,23 @@ CodeGenFunction::EmitDelegateCXXConstructorCall(const CXXConstructorDecl *Ctor,
ReturnValueSlot(), DelegateArgs, Ctor);
}
+namespace {
+ struct CallDelegatingCtorDtor : EHScopeStack::Cleanup {
+ const CXXDestructorDecl *Dtor;
+ llvm::Value *Addr;
+ CXXDtorType Type;
+
+ CallDelegatingCtorDtor(const CXXDestructorDecl *D, llvm::Value *Addr,
+ CXXDtorType Type)
+ : Dtor(D), Addr(Addr), Type(Type) {}
+
+ void Emit(CodeGenFunction &CGF, bool IsForEH) {
+ CGF.EmitCXXDestructorCall(Dtor, Type, /*ForVirtualBase=*/false,
+ Addr);
+ }
+ };
+}
+
void
CodeGenFunction::EmitDelegatingCXXConstructorCall(const CXXConstructorDecl *Ctor,
const FunctionArgList &Args) {
@@ -1279,8 +1387,17 @@ CodeGenFunction::EmitDelegatingCXXConstructorCall(const CXXConstructorDecl *Ctor
AggValueSlot AggSlot = AggValueSlot::forAddr(ThisPtr, false, /*Lifetime*/ true);
EmitAggExpr(Ctor->init_begin()[0]->getInit(), AggSlot);
-}
+ const CXXRecordDecl *ClassDecl = Ctor->getParent();
+ if (CGM.getLangOptions().Exceptions && !ClassDecl->hasTrivialDestructor()) {
+ CXXDtorType Type =
+ CurGD.getCtorType() == Ctor_Complete ? Dtor_Complete : Dtor_Base;
+
+ EHStack.pushCleanup<CallDelegatingCtorDtor>(EHCleanup,
+ ClassDecl->getDestructor(),
+ ThisPtr, Type);
+ }
+}
void CodeGenFunction::EmitCXXDestructorCall(const CXXDestructorDecl *DD,
CXXDtorType Type,
@@ -1494,3 +1611,136 @@ llvm::Value *CodeGenFunction::GetVTablePtr(llvm::Value *This,
llvm::Value *VTablePtrSrc = Builder.CreateBitCast(This, Ty->getPointerTo());
return Builder.CreateLoad(VTablePtrSrc, "vtable");
}
+
+static const CXXRecordDecl *getMostDerivedClassDecl(const Expr *Base) {
+ const Expr *E = Base;
+
+ while (true) {
+ E = E->IgnoreParens();
+ if (const CastExpr *CE = dyn_cast<CastExpr>(E)) {
+ if (CE->getCastKind() == CK_DerivedToBase ||
+ CE->getCastKind() == CK_UncheckedDerivedToBase ||
+ CE->getCastKind() == CK_NoOp) {
+ E = CE->getSubExpr();
+ continue;
+ }
+ }
+
+ break;
+ }
+
+ QualType DerivedType = E->getType();
+ if (const PointerType *PTy = DerivedType->getAs<PointerType>())
+ DerivedType = PTy->getPointeeType();
+
+ return cast<CXXRecordDecl>(DerivedType->castAs<RecordType>()->getDecl());
+}
+
+// FIXME: Ideally Expr::IgnoreParenNoopCasts should do this, but it doesn't do
+// quite what we want.
+static const Expr *skipNoOpCastsAndParens(const Expr *E) {
+ while (true) {
+ if (const ParenExpr *PE = dyn_cast<ParenExpr>(E)) {
+ E = PE->getSubExpr();
+ continue;
+ }
+
+ if (const CastExpr *CE = dyn_cast<CastExpr>(E)) {
+ if (CE->getCastKind() == CK_NoOp) {
+ E = CE->getSubExpr();
+ continue;
+ }
+ }
+ if (const UnaryOperator *UO = dyn_cast<UnaryOperator>(E)) {
+ if (UO->getOpcode() == UO_Extension) {
+ E = UO->getSubExpr();
+ continue;
+ }
+ }
+ return E;
+ }
+}
+
+/// canDevirtualizeMemberFunctionCall - Checks whether the given virtual member
+/// function call on the given expr can be devirtualized.
+/// expr can be devirtualized.
+static bool canDevirtualizeMemberFunctionCall(const Expr *Base,
+ const CXXMethodDecl *MD) {
+ // If the most derived class is marked final, we know that no subclass can
+ // override this member function and so we can devirtualize it. For example:
+ //
+ // struct A { virtual void f(); }
+ // struct B final : A { };
+ //
+ // void f(B *b) {
+ // b->f();
+ // }
+ //
+ const CXXRecordDecl *MostDerivedClassDecl = getMostDerivedClassDecl(Base);
+ if (MostDerivedClassDecl->hasAttr<FinalAttr>())
+ return true;
+
+ // If the member function is marked 'final', we know that it can't be
+ // overridden and can therefore devirtualize it.
+ if (MD->hasAttr<FinalAttr>())
+ return true;
+
+ // Similarly, if the class itself is marked 'final' it can't be overridden
+ // and we can therefore devirtualize the member function call.
+ if (MD->getParent()->hasAttr<FinalAttr>())
+ return true;
+
+ Base = skipNoOpCastsAndParens(Base);
+ if (const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(Base)) {
+ if (const VarDecl *VD = dyn_cast<VarDecl>(DRE->getDecl())) {
+ // This is a record decl. We know the type and can devirtualize it.
+ return VD->getType()->isRecordType();
+ }
+
+ return false;
+ }
+
+ // We can always devirtualize calls on temporary object expressions.
+ if (isa<CXXConstructExpr>(Base))
+ return true;
+
+ // And calls on bound temporaries.
+ if (isa<CXXBindTemporaryExpr>(Base))
+ return true;
+
+ // Check if this is a call expr that returns a record type.
+ if (const CallExpr *CE = dyn_cast<CallExpr>(Base))
+ return CE->getCallReturnType()->isRecordType();
+
+ // We can't devirtualize the call.
+ return false;
+}
+
+static bool UseVirtualCall(ASTContext &Context,
+ const CXXOperatorCallExpr *CE,
+ const CXXMethodDecl *MD) {
+ if (!MD->isVirtual())
+ return false;
+
+ // When building with -fapple-kext, all calls must go through the vtable since
+ // the kernel linker can do runtime patching of vtables.
+ if (Context.getLangOptions().AppleKext)
+ return true;
+
+ return !canDevirtualizeMemberFunctionCall(CE->getArg(0), MD);
+}
+
+llvm::Value *
+CodeGenFunction::EmitCXXOperatorMemberCallee(const CXXOperatorCallExpr *E,
+ const CXXMethodDecl *MD,
+ llvm::Value *This) {
+ const FunctionProtoType *FPT = MD->getType()->castAs<FunctionProtoType>();
+ const llvm::Type *Ty =
+ CGM.getTypes().GetFunctionType(CGM.getTypes().getFunctionInfo(MD),
+ FPT->isVariadic());
+
+ if (UseVirtualCall(getContext(), E, MD))
+ return BuildVirtualCall(MD, This, Ty);
+
+ return CGM.GetAddrOfFunction(MD, Ty);
+}
diff --git a/lib/CodeGen/CGDebugInfo.cpp b/lib/CodeGen/CGDebugInfo.cpp
index f2e1c02..98d30db 100644
--- a/lib/CodeGen/CGDebugInfo.cpp
+++ b/lib/CodeGen/CGDebugInfo.cpp
@@ -335,10 +335,12 @@ llvm::DIType CGDebugInfo::CreateType(const BuiltinType *BT) {
case BuiltinType::SChar: Encoding = llvm::dwarf::DW_ATE_signed_char; break;
case BuiltinType::UShort:
case BuiltinType::UInt:
+ case BuiltinType::UInt128:
case BuiltinType::ULong:
case BuiltinType::ULongLong: Encoding = llvm::dwarf::DW_ATE_unsigned; break;
case BuiltinType::Short:
case BuiltinType::Int:
+ case BuiltinType::Int128:
case BuiltinType::Long:
case BuiltinType::LongLong: Encoding = llvm::dwarf::DW_ATE_signed; break;
case BuiltinType::Bool: Encoding = llvm::dwarf::DW_ATE_boolean; break;
@@ -553,9 +555,12 @@ llvm::DIType CGDebugInfo::CreateType(const TypedefType *Ty,
// We don't set size information, but do specify where the typedef was
// declared.
unsigned Line = getLineNumber(Ty->getDecl()->getLocation());
- llvm::DIType DbgTy = DBuilder.createTypedef(Src, Ty->getDecl()->getName(),
- Unit, Line);
- return DbgTy;
+ const TypedefNameDecl *TyDecl = Ty->getDecl();
+ llvm::DIDescriptor TydefContext =
+ getContextDescriptor(cast<Decl>(Ty->getDecl()->getDeclContext()));
+
+ return
+ DBuilder.createTypedef(Src, TyDecl->getName(), Unit, Line, TydefContext);
}
llvm::DIType CGDebugInfo::CreateType(const FunctionType *Ty,
@@ -628,8 +633,7 @@ CollectRecordFields(const RecordDecl *record, llvm::DIFile tunit,
FieldDecl *field = *I;
if (IsMsStruct) {
// Zero-length bitfields following non-bitfield members are ignored
- if (CGM.getContext().ZeroBitfieldFollowsNonBitfield((field), LastFD) ||
- CGM.getContext().ZeroBitfieldFollowsBitfield((field), LastFD)) {
+ if (CGM.getContext().ZeroBitfieldFollowsNonBitfield((field), LastFD)) {
--fieldNo;
continue;
}
@@ -1240,9 +1244,13 @@ llvm::DIType CGDebugInfo::CreateType(const ObjCInterfaceType *Ty,
uint64_t Size = CGM.getContext().getTypeSize(Ty);
uint64_t Align = CGM.getContext().getTypeAlign(Ty);
+ unsigned Flags = 0;
+ if (ID->getImplementation())
+ Flags |= llvm::DIDescriptor::FlagObjcClassComplete;
+
llvm::DIType RealDecl =
DBuilder.createStructType(Unit, ID->getName(), DefUnit,
- Line, Size, Align, 0,
+ Line, Size, Align, Flags,
Elements, RuntimeLang);
// Now that we have a real decl for the struct, replace anything using the
@@ -1439,6 +1447,9 @@ static QualType UnwrapTypeForDebugInfo(QualType T) {
case Type::Decltype:
T = cast<DecltypeType>(T)->getUnderlyingType();
break;
+ case Type::UnaryTransform:
+ T = cast<UnaryTransformType>(T)->getUnderlyingType();
+ break;
case Type::Attributed:
T = cast<AttributedType>(T)->getEquivalentType();
break;
@@ -1554,6 +1565,7 @@ llvm::DIType CGDebugInfo::CreateTypeNode(QualType Ty,
case Type::TypeOfExpr:
case Type::TypeOf:
case Type::Decltype:
+ case Type::UnaryTransform:
case Type::Auto:
llvm_unreachable("type should have been unwrapped!");
return llvm::DIType();
@@ -1612,6 +1624,33 @@ llvm::DISubprogram CGDebugInfo::getFunctionDeclaration(const Decl *D) {
return llvm::DISubprogram();
}
+// getOrCreateFunctionType - Construct DIType. If it is a c++ method, include
+// implicit parameter "this".
+llvm::DIType CGDebugInfo::getOrCreateFunctionType(const Decl * D, QualType FnType,
+ llvm::DIFile F) {
+ if (const CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(D))
+ return getOrCreateMethodType(Method, F);
+ else if (const ObjCMethodDecl *OMethod = dyn_cast<ObjCMethodDecl>(D)) {
+ // Add "self" and "_cmd"
+ llvm::SmallVector<llvm::Value *, 16> Elts;
+
+ // First element is always return type. For 'void' functions it is NULL.
+ Elts.push_back(getOrCreateType(OMethod->getResultType(), F));
+ // "self" pointer is always first argument.
+ Elts.push_back(getOrCreateType(OMethod->getSelfDecl()->getType(), F));
+ // "cmd" pointer is always second argument.
+ Elts.push_back(getOrCreateType(OMethod->getCmdDecl()->getType(), F));
+ // Get rest of the arguments.
+ for (ObjCMethodDecl::param_iterator PI = OMethod->param_begin(),
+ PE = OMethod->param_end(); PI != PE; ++PI)
+ Elts.push_back(getOrCreateType((*PI)->getType(), F));
+
+ llvm::DIArray EltTypeArray = DBuilder.getOrCreateArray(Elts);
+ return DBuilder.createSubroutineType(F, EltTypeArray);
+ }
+ return getOrCreateType(FnType, F);
+}
+
/// EmitFunctionStart - Constructs the debug code for entering a function -
/// "llvm.dbg.func.start.".
void CGDebugInfo::EmitFunctionStart(GlobalDecl GD, QualType FnType,
@@ -1644,7 +1683,8 @@ void CGDebugInfo::EmitFunctionStart(GlobalDecl GD, QualType FnType,
}
Name = getFunctionName(FD);
// Use mangled name as linkage name for c/c++ functions.
- LinkageName = CGM.getMangledName(GD);
+ if (!Fn->hasInternalLinkage())
+ LinkageName = CGM.getMangledName(GD);
if (LinkageName == Name)
LinkageName = llvm::StringRef();
if (FD->hasPrototype())
@@ -1652,6 +1692,9 @@ void CGDebugInfo::EmitFunctionStart(GlobalDecl GD, QualType FnType,
if (const NamespaceDecl *NSDecl =
dyn_cast_or_null<NamespaceDecl>(FD->getDeclContext()))
FDContext = getOrCreateNameSpace(NSDecl);
+ else if (const RecordDecl *RDecl =
+ dyn_cast_or_null<RecordDecl>(FD->getDeclContext()))
+ FDContext = getContextDescriptor(cast<Decl>(RDecl->getDeclContext()));
// Collect template parameters.
TParamsArray = CollectFunctionTemplateParams(FD, Unit);
@@ -1672,11 +1715,10 @@ void CGDebugInfo::EmitFunctionStart(GlobalDecl GD, QualType FnType,
unsigned LineNo = getLineNumber(CurLoc);
if (D->isImplicit())
Flags |= llvm::DIDescriptor::FlagArtificial;
- llvm::DIType SPTy = getOrCreateType(FnType, Unit);
llvm::DISubprogram SPDecl = getFunctionDeclaration(D);
llvm::DISubprogram SP =
DBuilder.createFunction(FDContext, Name, LinkageName, Unit,
- LineNo, SPTy,
+ LineNo, getOrCreateFunctionType(D, FnType, Unit),
Fn->hasInternalLinkage(), true/*definition*/,
Flags, CGM.getLangOptions().Optimize, Fn,
TParamsArray, SPDecl);
diff --git a/lib/CodeGen/CGDebugInfo.h b/lib/CodeGen/CGDebugInfo.h
index 27d991b..6ec6b65 100644
--- a/lib/CodeGen/CGDebugInfo.h
+++ b/lib/CodeGen/CGDebugInfo.h
@@ -98,6 +98,8 @@ class CGDebugInfo {
llvm::DIType CreateEnumType(const EnumDecl *ED);
llvm::DIType getOrCreateMethodType(const CXXMethodDecl *Method,
llvm::DIFile F);
+ llvm::DIType getOrCreateFunctionType(const Decl *D, QualType FnType,
+ llvm::DIFile F);
llvm::DIType getOrCreateVTablePtrType(llvm::DIFile F);
llvm::DINameSpace getOrCreateNameSpace(const NamespaceDecl *N);
llvm::DIType CreatePointeeType(QualType PointeeTy, llvm::DIFile F);
diff --git a/lib/CodeGen/CGDecl.cpp b/lib/CodeGen/CGDecl.cpp
index c027375..8a1a853 100644
--- a/lib/CodeGen/CGDecl.cpp
+++ b/lib/CodeGen/CGDecl.cpp
@@ -51,6 +51,7 @@ void CodeGenFunction::EmitDecl(const Decl &D) {
case Decl::ImplicitParam:
case Decl::ClassTemplate:
case Decl::FunctionTemplate:
+ case Decl::TypeAliasTemplate:
case Decl::TemplateTemplateParm:
case Decl::ObjCMethod:
case Decl::ObjCCategory:
@@ -628,15 +629,14 @@ CodeGenFunction::EmitAutoVarAlloca(const VarDecl &D) {
emission.Address = DeclPtr;
// Emit debug info for local var declaration.
- if (CGDebugInfo *DI = getDebugInfo()) {
- assert(HaveInsertPoint() && "Unexpected unreachable point!");
-
- DI->setLocation(D.getLocation());
- if (Target.useGlobalsForAutomaticVariables()) {
- DI->EmitGlobalVariable(static_cast<llvm::GlobalVariable *>(DeclPtr), &D);
- } else
- DI->EmitDeclareOfAutoVariable(&D, DeclPtr, Builder);
- }
+ if (HaveInsertPoint())
+ if (CGDebugInfo *DI = getDebugInfo()) {
+ DI->setLocation(D.getLocation());
+ if (Target.useGlobalsForAutomaticVariables()) {
+ DI->EmitGlobalVariable(static_cast<llvm::GlobalVariable *>(DeclPtr), &D);
+ } else
+ DI->EmitDeclareOfAutoVariable(&D, DeclPtr, Builder);
+ }
return emission;
}
@@ -741,6 +741,7 @@ void CodeGenFunction::EmitAutoVarInit(const AutoVarEmission &emission) {
llvm::GlobalValue::InternalLinkage,
constant, Name, 0, false, 0);
GV->setAlignment(alignment.getQuantity());
+ GV->setUnnamedAddr(true);
llvm::Value *SrcPtr = GV;
if (SrcPtr->getType() != BP)
diff --git a/lib/CodeGen/CGDeclCXX.cpp b/lib/CodeGen/CGDeclCXX.cpp
index 45b0b96..178badd 100644
--- a/lib/CodeGen/CGDeclCXX.cpp
+++ b/lib/CodeGen/CGDeclCXX.cpp
@@ -117,19 +117,13 @@ CodeGenFunction::EmitCXXGlobalDtorRegistration(llvm::Constant *DtorFn,
return;
}
- std::vector<const llvm::Type *> Params;
- Params.push_back(Int8PtrTy);
-
// Get the destructor function type
const llvm::Type *DtorFnTy =
llvm::FunctionType::get(llvm::Type::getVoidTy(getLLVMContext()),
- Params, false);
+ Int8PtrTy, false);
DtorFnTy = llvm::PointerType::getUnqual(DtorFnTy);
- Params.clear();
- Params.push_back(DtorFnTy);
- Params.push_back(Int8PtrTy);
- Params.push_back(Int8PtrTy);
+ const llvm::Type *Params[] = { DtorFnTy, Int8PtrTy, Int8PtrTy };
// Get the __cxa_atexit function type
// extern "C" int __cxa_atexit ( void (*f)(void *), void *p, void *d );
@@ -248,6 +242,8 @@ CodeGenModule::EmitCXXGlobalInitFunc() {
&CXXGlobalInits[0],
CXXGlobalInits.size());
AddGlobalCtor(Fn);
+ CXXGlobalInits.clear();
+ PrioritizedCXXGlobalInits.clear();
}
void CodeGenModule::EmitCXXGlobalDtorFunc() {
diff --git a/lib/CodeGen/CGException.cpp b/lib/CodeGen/CGException.cpp
index 6cb9599..e8ad6da 100644
--- a/lib/CodeGen/CGException.cpp
+++ b/lib/CodeGen/CGException.cpp
@@ -112,11 +112,18 @@ static llvm::Constant *getUnexpectedFn(CodeGenFunction &CGF) {
return CGF.CGM.CreateRuntimeFunction(FTy, "__cxa_call_unexpected");
}
+llvm::Constant *CodeGenFunction::getUnwindResumeFn() {
+ const llvm::FunctionType *FTy =
+ llvm::FunctionType::get(VoidTy, Int8PtrTy, /*IsVarArgs=*/false);
+
+ if (CGM.getLangOptions().SjLjExceptions)
+ return CGM.CreateRuntimeFunction(FTy, "_Unwind_SjLj_Resume");
+ return CGM.CreateRuntimeFunction(FTy, "_Unwind_Resume");
+}
+
llvm::Constant *CodeGenFunction::getUnwindResumeOrRethrowFn() {
- const llvm::Type *Int8PtrTy = llvm::Type::getInt8PtrTy(getLLVMContext());
const llvm::FunctionType *FTy =
- llvm::FunctionType::get(llvm::Type::getVoidTy(getLLVMContext()), Int8PtrTy,
- /*IsVarArgs=*/false);
+ llvm::FunctionType::get(VoidTy, Int8PtrTy, /*IsVarArgs=*/false);
if (CGM.getLangOptions().SjLjExceptions)
return CGM.CreateRuntimeFunction(FTy, "_Unwind_SjLj_Resume_or_Rethrow");
@@ -354,13 +361,17 @@ static void EmitAnyExprToExn(CodeGenFunction &CGF, const Expr *e,
}
llvm::Value *CodeGenFunction::getExceptionSlot() {
- if (!ExceptionSlot) {
- const llvm::Type *i8p = llvm::Type::getInt8PtrTy(getLLVMContext());
- ExceptionSlot = CreateTempAlloca(i8p, "exn.slot");
- }
+ if (!ExceptionSlot)
+ ExceptionSlot = CreateTempAlloca(Int8PtrTy, "exn.slot");
return ExceptionSlot;
}
+llvm::Value *CodeGenFunction::getEHSelectorSlot() {
+ if (!EHSelectorSlot)
+ EHSelectorSlot = CreateTempAlloca(Int32Ty, "ehselector.slot");
+ return EHSelectorSlot;
+}
+
void CodeGenFunction::EmitCXXThrowExpr(const CXXThrowExpr *E) {
if (!E->getSubExpr()) {
if (getInvokeDest()) {
@@ -563,47 +574,59 @@ llvm::BasicBlock *CodeGenFunction::getInvokeDestImpl() {
return LP;
}
+// This code contains a hack to work around a design flaw in
+// LLVM's EH IR which breaks semantics after inlining. This same
+// hack is implemented in llvm-gcc.
+//
+// The LLVM EH abstraction is basically a thin veneer over the
+// traditional GCC zero-cost design: for each range of instructions
+// in the function, there is (at most) one "landing pad" with an
+// associated chain of EH actions. A language-specific personality
+// function interprets this chain of actions and (1) decides whether
+// or not to resume execution at the landing pad and (2) if so,
+// provides an integer indicating why it's stopping. In LLVM IR,
+// the association of a landing pad with a range of instructions is
+// achieved via an invoke instruction, the chain of actions becomes
+// the arguments to the @llvm.eh.selector call, and the selector
+// call returns the integer indicator. Other than the required
+// presence of two intrinsic function calls in the landing pad,
+// the IR exactly describes the layout of the output code.
+//
+// A principal advantage of this design is that it is completely
+// language-agnostic; in theory, the LLVM optimizers can treat
+// landing pads neutrally, and targets need only know how to lower
+// the intrinsics to have a functioning exceptions system (assuming
+// that platform exceptions follow something approximately like the
+// GCC design). Unfortunately, landing pads cannot be combined in a
+// language-agnostic way: given selectors A and B, there is no way
+// to make a single landing pad which faithfully represents the
+// semantics of propagating an exception first through A, then
+// through B, without knowing how the personality will interpret the
+// (lowered form of the) selectors. This means that inlining has no
+// choice but to crudely chain invokes (i.e., to ignore invokes in
+// the inlined function, but to turn all unwindable calls into
+// invokes), which is only semantically valid if every unwind stops
+// at every landing pad.
+//
+// Therefore, the invoke-inline hack is to guarantee that every
+// landing pad has a catch-all.
+enum CleanupHackLevel_t {
+ /// A level of hack that requires that all landing pads have
+ /// catch-alls.
+ CHL_MandatoryCatchall,
+
+ /// A level of hack that requires that all landing pads handle
+ /// cleanups.
+ CHL_MandatoryCleanup,
+
+ /// No hacks at all; ideal IR generation.
+ CHL_Ideal
+};
+const CleanupHackLevel_t CleanupHackLevel = CHL_MandatoryCleanup;
+
llvm::BasicBlock *CodeGenFunction::EmitLandingPad() {
assert(EHStack.requiresLandingPad());
- // This function contains a hack to work around a design flaw in
- // LLVM's EH IR which breaks semantics after inlining. This same
- // hack is implemented in llvm-gcc.
- //
- // The LLVM EH abstraction is basically a thin veneer over the
- // traditional GCC zero-cost design: for each range of instructions
- // in the function, there is (at most) one "landing pad" with an
- // associated chain of EH actions. A language-specific personality
- // function interprets this chain of actions and (1) decides whether
- // or not to resume execution at the landing pad and (2) if so,
- // provides an integer indicating why it's stopping. In LLVM IR,
- // the association of a landing pad with a range of instructions is
- // achieved via an invoke instruction, the chain of actions becomes
- // the arguments to the @llvm.eh.selector call, and the selector
- // call returns the integer indicator. Other than the required
- // presence of two intrinsic function calls in the landing pad,
- // the IR exactly describes the layout of the output code.
- //
- // A principal advantage of this design is that it is completely
- // language-agnostic; in theory, the LLVM optimizers can treat
- // landing pads neutrally, and targets need only know how to lower
- // the intrinsics to have a functioning exceptions system (assuming
- // that platform exceptions follow something approximately like the
- // GCC design). Unfortunately, landing pads cannot be combined in a
- // language-agnostic way: given selectors A and B, there is no way
- // to make a single landing pad which faithfully represents the
- // semantics of propagating an exception first through A, then
- // through B, without knowing how the personality will interpret the
- // (lowered form of the) selectors. This means that inlining has no
- // choice but to crudely chain invokes (i.e., to ignore invokes in
- // the inlined function, but to turn all unwindable calls into
- // invokes), which is only semantically valid if every unwind stops
- // at every landing pad.
- //
- // Therefore, the invoke-inline hack is to guarantee that every
- // landing pad has a catch-all.
- const bool UseInvokeInlineHack = true;
-
for (EHScopeStack::iterator ir = EHStack.begin(); ; ) {
assert(ir != EHStack.end() &&
"stack requiring landing pad is nothing but non-EH scopes?");
@@ -736,16 +759,23 @@ llvm::BasicBlock *CodeGenFunction::EmitLandingPad() {
EHSelector.append(EHFilters.begin(), EHFilters.end());
// Also check whether we need a cleanup.
- if (UseInvokeInlineHack || HasEHCleanup)
- EHSelector.push_back(UseInvokeInlineHack
+ if (CleanupHackLevel == CHL_MandatoryCatchall || HasEHCleanup)
+ EHSelector.push_back(CleanupHackLevel == CHL_MandatoryCatchall
? getCatchAllValue(*this)
: getCleanupValue(*this));
// Otherwise, signal that we at least have cleanups.
- } else if (UseInvokeInlineHack || HasEHCleanup) {
- EHSelector.push_back(UseInvokeInlineHack
+ } else if (CleanupHackLevel == CHL_MandatoryCatchall || HasEHCleanup) {
+ EHSelector.push_back(CleanupHackLevel == CHL_MandatoryCatchall
? getCatchAllValue(*this)
: getCleanupValue(*this));
+
+ // At the MandatoryCleanup hack level, we don't need to actually
+ // spuriously tell the unwinder that we have cleanups, but we do
+ // need to always be prepared to handle cleanups.
+ } else if (CleanupHackLevel == CHL_MandatoryCleanup) {
+ // Just don't decrement LastToEmitInLoop.
+
} else {
assert(LastToEmitInLoop > 2);
LastToEmitInLoop--;
@@ -758,6 +788,10 @@ llvm::BasicBlock *CodeGenFunction::EmitLandingPad() {
Builder.CreateCall(CGM.getIntrinsic(llvm::Intrinsic::eh_selector),
EHSelector.begin(), EHSelector.end(), "eh.selector");
Selection->setDoesNotThrow();
+
+ // Save the selector value in mandatory-cleanup mode.
+ if (CleanupHackLevel == CHL_MandatoryCleanup)
+ Builder.CreateStore(Selection, getEHSelectorSlot());
// Select the right handler.
llvm::Value *llvm_eh_typeid_for =
@@ -833,22 +867,13 @@ llvm::BasicBlock *CodeGenFunction::EmitLandingPad() {
// If there was a cleanup, we'll need to actually check whether we
// landed here because the filter triggered.
- if (UseInvokeInlineHack || HasEHCleanup) {
- llvm::BasicBlock *RethrowBB = createBasicBlock("cleanup");
+ if (CleanupHackLevel != CHL_Ideal || HasEHCleanup) {
llvm::BasicBlock *UnexpectedBB = createBasicBlock("ehspec.unexpected");
- llvm::Constant *Zero = llvm::ConstantInt::get(Builder.getInt32Ty(), 0);
+ llvm::Constant *Zero = llvm::ConstantInt::get(Int32Ty, 0);
llvm::Value *FailsFilter =
Builder.CreateICmpSLT(SavedSelection, Zero, "ehspec.fails");
- Builder.CreateCondBr(FailsFilter, UnexpectedBB, RethrowBB);
-
- // The rethrow block is where we land if this was a cleanup.
- // TODO: can this be _Unwind_Resume if the InvokeInlineHack is off?
- EmitBlock(RethrowBB);
- Builder.CreateCall(getUnwindResumeOrRethrowFn(),
- Builder.CreateLoad(getExceptionSlot()))
- ->setDoesNotReturn();
- Builder.CreateUnreachable();
+ Builder.CreateCondBr(FailsFilter, UnexpectedBB, getRethrowDest().getBlock());
EmitBlock(UnexpectedBB);
}
@@ -863,7 +888,7 @@ llvm::BasicBlock *CodeGenFunction::EmitLandingPad() {
Builder.CreateUnreachable();
// ...or a normal catch handler...
- } else if (!UseInvokeInlineHack && !HasEHCleanup) {
+ } else if (CleanupHackLevel == CHL_Ideal && !HasEHCleanup) {
llvm::Value *Type = EHSelector.back();
EmitBranchThroughEHCleanup(EHHandlers[Type]);
@@ -1440,14 +1465,39 @@ CodeGenFunction::UnwindDest CodeGenFunction::getRethrowDest() {
// This can always be a call because we necessarily didn't find
// anything on the EH stack which needs our help.
llvm::StringRef RethrowName = Personality.getCatchallRethrowFnName();
- llvm::Constant *RethrowFn;
- if (!RethrowName.empty())
- RethrowFn = getCatchallRethrowFn(*this, RethrowName);
- else
- RethrowFn = getUnwindResumeOrRethrowFn();
+ if (!RethrowName.empty()) {
+ Builder.CreateCall(getCatchallRethrowFn(*this, RethrowName),
+ Builder.CreateLoad(getExceptionSlot()))
+ ->setDoesNotReturn();
+ } else {
+ llvm::Value *Exn = Builder.CreateLoad(getExceptionSlot());
+
+ switch (CleanupHackLevel) {
+ case CHL_MandatoryCatchall:
+ // In mandatory-catchall mode, we need to use
+ // _Unwind_Resume_or_Rethrow, or whatever the personality's
+ // equivalent is.
+ Builder.CreateCall(getUnwindResumeOrRethrowFn(), Exn)
+ ->setDoesNotReturn();
+ break;
+ case CHL_MandatoryCleanup: {
+ // In mandatory-cleanup mode, we should use llvm.eh.resume.
+ llvm::Value *Selector = Builder.CreateLoad(getEHSelectorSlot());
+ Builder.CreateCall2(CGM.getIntrinsic(llvm::Intrinsic::eh_resume),
+ Exn, Selector)
+ ->setDoesNotReturn();
+ break;
+ }
+ case CHL_Ideal:
+ // In an idealized mode where we don't have to worry about the
+ // optimizer combining landing pads, we should just use
+ // _Unwind_Resume (or the personality's equivalent).
+ Builder.CreateCall(getUnwindResumeFn(), Exn)
+ ->setDoesNotReturn();
+ break;
+ }
+ }
- Builder.CreateCall(RethrowFn, Builder.CreateLoad(getExceptionSlot()))
- ->setDoesNotReturn();
Builder.CreateUnreachable();
Builder.restoreIP(SavedIP);
diff --git a/lib/CodeGen/CGExpr.cpp b/lib/CodeGen/CGExpr.cpp
index bc2cd35..2f6b55b 100644
--- a/lib/CodeGen/CGExpr.cpp
+++ b/lib/CodeGen/CGExpr.cpp
@@ -1390,7 +1390,7 @@ LValue CodeGenFunction::EmitArraySubscriptExpr(const ArraySubscriptExpr *E) {
// The index must always be an integer, which is not an aggregate. Emit it.
llvm::Value *Idx = EmitScalarExpr(E->getIdx());
QualType IdxTy = E->getIdx()->getType();
- bool IdxSigned = IdxTy->isSignedIntegerType();
+ bool IdxSigned = IdxTy->isSignedIntegerOrEnumerationType();
// If the base is a vector type, then we are forming a vector element lvalue
// with this subscript.
@@ -1635,7 +1635,8 @@ LValue CodeGenFunction::EmitLValueForAnonRecordField(llvm::Value *BaseValue,
IndirectFieldDecl::chain_iterator I = Field->chain_begin(),
IEnd = Field->chain_end();
while (true) {
- LValue LV = EmitLValueForField(BaseValue, cast<FieldDecl>(*I), CVRQualifiers);
+ LValue LV = EmitLValueForField(BaseValue, cast<FieldDecl>(*I),
+ CVRQualifiers);
if (++I == IEnd) return LV;
assert(LV.isSimple());
diff --git a/lib/CodeGen/CGExprAgg.cpp b/lib/CodeGen/CGExprAgg.cpp
index 29c7688..d8da642 100644
--- a/lib/CodeGen/CGExprAgg.cpp
+++ b/lib/CodeGen/CGExprAgg.cpp
@@ -642,7 +642,7 @@ void AggExprEmitter::VisitInitListExpr(InitListExpr *E) {
if (const RecordType *RT = CGF.getContext()
.getBaseElementType(ElementType)->getAs<RecordType>()) {
const CXXRecordDecl *RD = cast<CXXRecordDecl>(RT->getDecl());
- hasNonTrivialCXXConstructor = !RD->hasTrivialConstructor();
+ hasNonTrivialCXXConstructor = !RD->hasTrivialDefaultConstructor();
}
// FIXME: were we intentionally ignoring address spaces and GC attributes?
diff --git a/lib/CodeGen/CGExprCXX.cpp b/lib/CodeGen/CGExprCXX.cpp
index bdaa873..81fee67 100644
--- a/lib/CodeGen/CGExprCXX.cpp
+++ b/lib/CodeGen/CGExprCXX.cpp
@@ -345,18 +345,7 @@ CodeGenFunction::EmitCXXOperatorMemberCallExpr(const CXXOperatorCallExpr *E,
}
}
- const FunctionProtoType *FPT = MD->getType()->getAs<FunctionProtoType>();
- const llvm::Type *Ty =
- CGM.getTypes().GetFunctionType(CGM.getTypes().getFunctionInfo(MD),
- FPT->isVariadic());
- llvm::Value *Callee;
- if (MD->isVirtual() &&
- !canDevirtualizeMemberFunctionCalls(getContext(),
- E->getArg(0), MD))
- Callee = BuildVirtualCall(MD, This, Ty);
- else
- Callee = CGM.GetAddrOfFunction(MD, Ty);
-
+ llvm::Value *Callee = EmitCXXOperatorMemberCallee(E, MD, This);
return EmitCXXMemberCall(MD, Callee, ReturnValue, This, /*VTT=*/0,
E->arg_begin() + 1, E->arg_end());
}
@@ -403,18 +392,26 @@ CodeGenFunction::EmitCXXConstructExpr(const CXXConstructExpr *E,
E->arg_begin(), E->arg_end());
}
else {
- CXXCtorType Type;
- CXXConstructExpr::ConstructionKind K = E->getConstructionKind();
- if (K == CXXConstructExpr::CK_Delegating) {
+ CXXCtorType Type = Ctor_Complete;
+ bool ForVirtualBase = false;
+
+ switch (E->getConstructionKind()) {
+ case CXXConstructExpr::CK_Delegating:
// We should be emitting a constructor; GlobalDecl will assert this
Type = CurGD.getCtorType();
- } else {
- Type = (E->getConstructionKind() == CXXConstructExpr::CK_Complete)
- ? Ctor_Complete : Ctor_Base;
- }
+ break;
+
+ case CXXConstructExpr::CK_Complete:
+ Type = Ctor_Complete;
+ break;
+
+ case CXXConstructExpr::CK_VirtualBase:
+ ForVirtualBase = true;
+ // fall-through
- bool ForVirtualBase =
- E->getConstructionKind() == CXXConstructExpr::CK_VirtualBase;
+ case CXXConstructExpr::CK_NonVirtualBase:
+ Type = Ctor_Base;
+ }
// Call the constructor.
EmitCXXConstructorCall(CD, Type, ForVirtualBase, Dest.getAddr(),
@@ -447,204 +444,256 @@ CodeGenFunction::EmitSynthesizedCXXCopyCtor(llvm::Value *Dest,
E->arg_begin(), E->arg_end());
}
-/// Check whether the given operator new[] is the global placement
-/// operator new[].
-static bool IsPlacementOperatorNewArray(ASTContext &Ctx,
- const FunctionDecl *Fn) {
- // Must be in global scope. Note that allocation functions can't be
- // declared in namespaces.
- if (!Fn->getDeclContext()->getRedeclContext()->isFileContext())
- return false;
-
- // Signature must be void *operator new[](size_t, void*).
- // The size_t is common to all operator new[]s.
- if (Fn->getNumParams() != 2)
- return false;
-
- CanQualType ParamType = Ctx.getCanonicalType(Fn->getParamDecl(1)->getType());
- return (ParamType == Ctx.VoidPtrTy);
-}
-
static CharUnits CalculateCookiePadding(CodeGenFunction &CGF,
const CXXNewExpr *E) {
if (!E->isArray())
return CharUnits::Zero();
- // No cookie is required if the new operator being used is
- // ::operator new[](size_t, void*).
- const FunctionDecl *OperatorNew = E->getOperatorNew();
- if (IsPlacementOperatorNewArray(CGF.getContext(), OperatorNew))
+ // No cookie is required if the operator new[] being used is the
+ // reserved placement operator new[].
+ if (E->getOperatorNew()->isReservedGlobalPlacementOperator())
return CharUnits::Zero();
return CGF.CGM.getCXXABI().GetArrayCookieSize(E);
}
-static llvm::Value *EmitCXXNewAllocSize(ASTContext &Context,
- CodeGenFunction &CGF,
- const CXXNewExpr *E,
- llvm::Value *&NumElements,
- llvm::Value *&SizeWithoutCookie) {
- QualType ElemType = E->getAllocatedType();
-
- const llvm::IntegerType *SizeTy =
- cast<llvm::IntegerType>(CGF.ConvertType(CGF.getContext().getSizeType()));
-
- CharUnits TypeSize = CGF.getContext().getTypeSizeInChars(ElemType);
-
- if (!E->isArray()) {
- SizeWithoutCookie = llvm::ConstantInt::get(SizeTy, TypeSize.getQuantity());
- return SizeWithoutCookie;
+static llvm::Value *EmitCXXNewAllocSize(CodeGenFunction &CGF,
+ const CXXNewExpr *e,
+ llvm::Value *&numElements,
+ llvm::Value *&sizeWithoutCookie) {
+ QualType type = e->getAllocatedType();
+
+ if (!e->isArray()) {
+ CharUnits typeSize = CGF.getContext().getTypeSizeInChars(type);
+ sizeWithoutCookie
+ = llvm::ConstantInt::get(CGF.SizeTy, typeSize.getQuantity());
+ return sizeWithoutCookie;
}
+ // The width of size_t.
+ unsigned sizeWidth = CGF.SizeTy->getBitWidth();
+
// Figure out the cookie size.
- CharUnits CookieSize = CalculateCookiePadding(CGF, E);
+ llvm::APInt cookieSize(sizeWidth,
+ CalculateCookiePadding(CGF, e).getQuantity());
// Emit the array size expression.
// We multiply the size of all dimensions for NumElements.
// e.g for 'int[2][3]', ElemType is 'int' and NumElements is 6.
- NumElements = CGF.EmitScalarExpr(E->getArraySize());
- assert(NumElements->getType() == SizeTy && "element count not a size_t");
-
- uint64_t ArraySizeMultiplier = 1;
+ numElements = CGF.EmitScalarExpr(e->getArraySize());
+ assert(isa<llvm::IntegerType>(numElements->getType()));
+
+ // The number of elements can be have an arbitrary integer type;
+ // essentially, we need to multiply it by a constant factor, add a
+ // cookie size, and verify that the result is representable as a
+ // size_t. That's just a gloss, though, and it's wrong in one
+ // important way: if the count is negative, it's an error even if
+ // the cookie size would bring the total size >= 0.
+ bool isSigned
+ = e->getArraySize()->getType()->isSignedIntegerOrEnumerationType();
+ const llvm::IntegerType *numElementsType
+ = cast<llvm::IntegerType>(numElements->getType());
+ unsigned numElementsWidth = numElementsType->getBitWidth();
+
+ // Compute the constant factor.
+ llvm::APInt arraySizeMultiplier(sizeWidth, 1);
while (const ConstantArrayType *CAT
- = CGF.getContext().getAsConstantArrayType(ElemType)) {
- ElemType = CAT->getElementType();
- ArraySizeMultiplier *= CAT->getSize().getZExtValue();
+ = CGF.getContext().getAsConstantArrayType(type)) {
+ type = CAT->getElementType();
+ arraySizeMultiplier *= CAT->getSize();
}
- llvm::Value *Size;
+ CharUnits typeSize = CGF.getContext().getTypeSizeInChars(type);
+ llvm::APInt typeSizeMultiplier(sizeWidth, typeSize.getQuantity());
+ typeSizeMultiplier *= arraySizeMultiplier;
+
+ // This will be a size_t.
+ llvm::Value *size;
// If someone is doing 'new int[42]' there is no need to do a dynamic check.
// Don't bloat the -O0 code.
- if (llvm::ConstantInt *NumElementsC =
- dyn_cast<llvm::ConstantInt>(NumElements)) {
- llvm::APInt NEC = NumElementsC->getValue();
- unsigned SizeWidth = NEC.getBitWidth();
-
- // Determine if there is an overflow here by doing an extended multiply.
- NEC = NEC.zext(SizeWidth*2);
- llvm::APInt SC(SizeWidth*2, TypeSize.getQuantity());
- SC *= NEC;
-
- if (!CookieSize.isZero()) {
- // Save the current size without a cookie. We don't care if an
- // overflow's already happened because SizeWithoutCookie isn't
- // used if the allocator returns null or throws, as it should
- // always do on an overflow.
- llvm::APInt SWC = SC.trunc(SizeWidth);
- SizeWithoutCookie = llvm::ConstantInt::get(SizeTy, SWC);
-
- // Add the cookie size.
- SC += llvm::APInt(SizeWidth*2, CookieSize.getQuantity());
+ if (llvm::ConstantInt *numElementsC =
+ dyn_cast<llvm::ConstantInt>(numElements)) {
+ const llvm::APInt &count = numElementsC->getValue();
+
+ bool hasAnyOverflow = false;
+
+ // If 'count' was a negative number, it's an overflow.
+ if (isSigned && count.isNegative())
+ hasAnyOverflow = true;
+
+ // We want to do all this arithmetic in size_t. If numElements is
+ // wider than that, check whether it's already too big, and if so,
+ // overflow.
+ else if (numElementsWidth > sizeWidth &&
+ numElementsWidth - sizeWidth > count.countLeadingZeros())
+ hasAnyOverflow = true;
+
+ // Okay, compute a count at the right width.
+ llvm::APInt adjustedCount = count.zextOrTrunc(sizeWidth);
+
+ // Scale numElements by that. This might overflow, but we don't
+ // care because it only overflows if allocationSize does, too, and
+ // if that overflows then we shouldn't use this.
+ numElements = llvm::ConstantInt::get(CGF.SizeTy,
+ adjustedCount * arraySizeMultiplier);
+
+ // Compute the size before cookie, and track whether it overflowed.
+ bool overflow;
+ llvm::APInt allocationSize
+ = adjustedCount.umul_ov(typeSizeMultiplier, overflow);
+ hasAnyOverflow |= overflow;
+
+ // Add in the cookie, and check whether it's overflowed.
+ if (cookieSize != 0) {
+ // Save the current size without a cookie. This shouldn't be
+ // used if there was overflow.
+ sizeWithoutCookie = llvm::ConstantInt::get(CGF.SizeTy, allocationSize);
+
+ allocationSize = allocationSize.uadd_ov(cookieSize, overflow);
+ hasAnyOverflow |= overflow;
}
-
- if (SC.countLeadingZeros() >= SizeWidth) {
- SC = SC.trunc(SizeWidth);
- Size = llvm::ConstantInt::get(SizeTy, SC);
+
+ // On overflow, produce a -1 so operator new will fail.
+ if (hasAnyOverflow) {
+ size = llvm::Constant::getAllOnesValue(CGF.SizeTy);
} else {
- // On overflow, produce a -1 so operator new throws.
- Size = llvm::Constant::getAllOnesValue(SizeTy);
+ size = llvm::ConstantInt::get(CGF.SizeTy, allocationSize);
}
- // Scale NumElements while we're at it.
- uint64_t N = NEC.getZExtValue() * ArraySizeMultiplier;
- NumElements = llvm::ConstantInt::get(SizeTy, N);
-
- // Otherwise, we don't need to do an overflow-checked multiplication if
- // we're multiplying by one.
- } else if (TypeSize.isOne()) {
- assert(ArraySizeMultiplier == 1);
-
- Size = NumElements;
-
- // If we need a cookie, add its size in with an overflow check.
- // This is maybe a little paranoid.
- if (!CookieSize.isZero()) {
- SizeWithoutCookie = Size;
+ // Otherwise, we might need to use the overflow intrinsics.
+ } else {
+ // There are up to four conditions we need to test for:
+ // 1) if isSigned, we need to check whether numElements is negative;
+ // 2) if numElementsWidth > sizeWidth, we need to check whether
+ // numElements is larger than something representable in size_t;
+ // 3) we need to compute
+ // sizeWithoutCookie := numElements * typeSizeMultiplier
+ // and check whether it overflows; and
+ // 4) if we need a cookie, we need to compute
+ // size := sizeWithoutCookie + cookieSize
+ // and check whether it overflows.
+
+ llvm::Value *hasOverflow = 0;
+
+ // If numElementsWidth > sizeWidth, then one way or another, we're
+ // going to have to do a comparison for (2), and this happens to
+ // take care of (1), too.
+ if (numElementsWidth > sizeWidth) {
+ llvm::APInt threshold(numElementsWidth, 1);
+ threshold <<= sizeWidth;
+
+ llvm::Value *thresholdV
+ = llvm::ConstantInt::get(numElementsType, threshold);
+
+ hasOverflow = CGF.Builder.CreateICmpUGE(numElements, thresholdV);
+ numElements = CGF.Builder.CreateTrunc(numElements, CGF.SizeTy);
+
+ // Otherwise, if we're signed, we want to sext up to size_t.
+ } else if (isSigned) {
+ if (numElementsWidth < sizeWidth)
+ numElements = CGF.Builder.CreateSExt(numElements, CGF.SizeTy);
+
+ // If there's a non-1 type size multiplier, then we can do the
+ // signedness check at the same time as we do the multiply
+ // because a negative number times anything will cause an
+ // unsigned overflow. Otherwise, we have to do it here.
+ if (typeSizeMultiplier == 1)
+ hasOverflow = CGF.Builder.CreateICmpSLT(numElements,
+ llvm::ConstantInt::get(CGF.SizeTy, 0));
+
+ // Otherwise, zext up to size_t if necessary.
+ } else if (numElementsWidth < sizeWidth) {
+ numElements = CGF.Builder.CreateZExt(numElements, CGF.SizeTy);
+ }
- llvm::Value *CookieSizeV
- = llvm::ConstantInt::get(SizeTy, CookieSize.getQuantity());
+ assert(numElements->getType() == CGF.SizeTy);
- const llvm::Type *Types[] = { SizeTy };
- llvm::Value *UAddF
- = CGF.CGM.getIntrinsic(llvm::Intrinsic::uadd_with_overflow, Types, 1);
- llvm::Value *AddRes
- = CGF.Builder.CreateCall2(UAddF, Size, CookieSizeV);
+ size = numElements;
- Size = CGF.Builder.CreateExtractValue(AddRes, 0);
- llvm::Value *DidOverflow = CGF.Builder.CreateExtractValue(AddRes, 1);
- Size = CGF.Builder.CreateSelect(DidOverflow,
- llvm::ConstantInt::get(SizeTy, -1),
- Size);
+ // Multiply by the type size if necessary. This multiplier
+ // includes all the factors for nested arrays.
+ //
+ // This step also causes numElements to be scaled up by the
+ // nested-array factor if necessary. Overflow on this computation
+ // can be ignored because the result shouldn't be used if
+ // allocation fails.
+ if (typeSizeMultiplier != 1) {
+ const llvm::Type *intrinsicTypes[] = { CGF.SizeTy };
+ llvm::Value *umul_with_overflow
+ = CGF.CGM.getIntrinsic(llvm::Intrinsic::umul_with_overflow,
+ intrinsicTypes, 1);
+
+ llvm::Value *tsmV =
+ llvm::ConstantInt::get(CGF.SizeTy, typeSizeMultiplier);
+ llvm::Value *result =
+ CGF.Builder.CreateCall2(umul_with_overflow, size, tsmV);
+
+ llvm::Value *overflowed = CGF.Builder.CreateExtractValue(result, 1);
+ if (hasOverflow)
+ hasOverflow = CGF.Builder.CreateOr(hasOverflow, overflowed);
+ else
+ hasOverflow = overflowed;
+
+ size = CGF.Builder.CreateExtractValue(result, 0);
+
+ // Also scale up numElements by the array size multiplier.
+ if (arraySizeMultiplier != 1) {
+ // If the base element type size is 1, then we can re-use the
+ // multiply we just did.
+ if (typeSize.isOne()) {
+ assert(arraySizeMultiplier == typeSizeMultiplier);
+ numElements = size;
+
+ // Otherwise we need a separate multiply.
+ } else {
+ llvm::Value *asmV =
+ llvm::ConstantInt::get(CGF.SizeTy, arraySizeMultiplier);
+ numElements = CGF.Builder.CreateMul(numElements, asmV);
+ }
+ }
+ } else {
+ // numElements doesn't need to be scaled.
+ assert(arraySizeMultiplier == 1);
}
+
+ // Add in the cookie size if necessary.
+ if (cookieSize != 0) {
+ sizeWithoutCookie = size;
+
+ const llvm::Type *intrinsicTypes[] = { CGF.SizeTy };
+ llvm::Value *uadd_with_overflow
+ = CGF.CGM.getIntrinsic(llvm::Intrinsic::uadd_with_overflow,
+ intrinsicTypes, 1);
+
+ llvm::Value *cookieSizeV = llvm::ConstantInt::get(CGF.SizeTy, cookieSize);
+ llvm::Value *result =
+ CGF.Builder.CreateCall2(uadd_with_overflow, size, cookieSizeV);
+
+ llvm::Value *overflowed = CGF.Builder.CreateExtractValue(result, 1);
+ if (hasOverflow)
+ hasOverflow = CGF.Builder.CreateOr(hasOverflow, overflowed);
+ else
+ hasOverflow = overflowed;
- // Otherwise use the int.umul.with.overflow intrinsic.
- } else {
- llvm::Value *OutermostElementSize
- = llvm::ConstantInt::get(SizeTy, TypeSize.getQuantity());
-
- llvm::Value *NumOutermostElements = NumElements;
-
- // Scale NumElements by the array size multiplier. This might
- // overflow, but only if the multiplication below also overflows,
- // in which case this multiplication isn't used.
- if (ArraySizeMultiplier != 1)
- NumElements = CGF.Builder.CreateMul(NumElements,
- llvm::ConstantInt::get(SizeTy, ArraySizeMultiplier));
-
- // The requested size of the outermost array is non-constant.
- // Multiply that by the static size of the elements of that array;
- // on unsigned overflow, set the size to -1 to trigger an
- // exception from the allocation routine. This is sufficient to
- // prevent buffer overruns from the allocator returning a
- // seemingly valid pointer to insufficient space. This idea comes
- // originally from MSVC, and GCC has an open bug requesting
- // similar behavior:
- // http://gcc.gnu.org/bugzilla/show_bug.cgi?id=19351
- //
- // This will not be sufficient for C++0x, which requires a
- // specific exception class (std::bad_array_new_length).
- // That will require ABI support that has not yet been specified.
- const llvm::Type *Types[] = { SizeTy };
- llvm::Value *UMulF
- = CGF.CGM.getIntrinsic(llvm::Intrinsic::umul_with_overflow, Types, 1);
- llvm::Value *MulRes = CGF.Builder.CreateCall2(UMulF, NumOutermostElements,
- OutermostElementSize);
-
- // The overflow bit.
- llvm::Value *DidOverflow = CGF.Builder.CreateExtractValue(MulRes, 1);
-
- // The result of the multiplication.
- Size = CGF.Builder.CreateExtractValue(MulRes, 0);
-
- // If we have a cookie, we need to add that size in, too.
- if (!CookieSize.isZero()) {
- SizeWithoutCookie = Size;
-
- llvm::Value *CookieSizeV
- = llvm::ConstantInt::get(SizeTy, CookieSize.getQuantity());
- llvm::Value *UAddF
- = CGF.CGM.getIntrinsic(llvm::Intrinsic::uadd_with_overflow, Types, 1);
- llvm::Value *AddRes
- = CGF.Builder.CreateCall2(UAddF, SizeWithoutCookie, CookieSizeV);
-
- Size = CGF.Builder.CreateExtractValue(AddRes, 0);
-
- llvm::Value *AddDidOverflow = CGF.Builder.CreateExtractValue(AddRes, 1);
- DidOverflow = CGF.Builder.CreateOr(DidOverflow, AddDidOverflow);
+ size = CGF.Builder.CreateExtractValue(result, 0);
}
- Size = CGF.Builder.CreateSelect(DidOverflow,
- llvm::ConstantInt::get(SizeTy, -1),
- Size);
+ // If we had any possibility of dynamic overflow, make a select to
+ // overwrite 'size' with an all-ones value, which should cause
+ // operator new to throw.
+ if (hasOverflow)
+ size = CGF.Builder.CreateSelect(hasOverflow,
+ llvm::Constant::getAllOnesValue(CGF.SizeTy),
+ size);
}
- if (CookieSize.isZero())
- SizeWithoutCookie = Size;
+ if (cookieSize == 0)
+ sizeWithoutCookie = size;
else
- assert(SizeWithoutCookie && "didn't set SizeWithoutCookie?");
+ assert(sizeWithoutCookie && "didn't set sizeWithoutCookie?");
- return Size;
+ return size;
}
static void StoreAnyExprIntoOneUnit(CodeGenFunction &CGF, const CXXNewExpr *E,
@@ -741,7 +790,7 @@ static void EmitNewInitializer(CodeGenFunction &CGF, const CXXNewExpr *E,
if (E->isArray()) {
if (CXXConstructorDecl *Ctor = E->getConstructor()) {
bool RequiresZeroInitialization = false;
- if (Ctor->getParent()->hasTrivialConstructor()) {
+ if (Ctor->getParent()->hasTrivialDefaultConstructor()) {
// If new expression did not specify value-initialization, then there
// is no initialization.
if (!E->hasInitializer() || Ctor->getParent()->isEmpty())
@@ -972,8 +1021,7 @@ llvm::Value *CodeGenFunction::EmitCXXNewExpr(const CXXNewExpr *E) {
llvm::Value *numElements = 0;
llvm::Value *allocSizeWithoutCookie = 0;
llvm::Value *allocSize =
- EmitCXXNewAllocSize(getContext(), *this, E, numElements,
- allocSizeWithoutCookie);
+ EmitCXXNewAllocSize(*this, E, numElements, allocSizeWithoutCookie);
allocatorArgs.add(RValue::get(allocSize), sizeType);
@@ -1007,11 +1055,19 @@ llvm::Value *CodeGenFunction::EmitCXXNewExpr(const CXXNewExpr *E) {
EmitCallArg(allocatorArgs, *placementArg, placementArg->getType());
}
- // Emit the allocation call.
- RValue RV =
- EmitCall(CGM.getTypes().getFunctionInfo(allocatorArgs, allocatorType),
- CGM.GetAddrOfFunction(allocator), ReturnValueSlot(),
- allocatorArgs, allocator);
+ // Emit the allocation call. If the allocator is a global placement
+ // operator, just "inline" it directly.
+ RValue RV;
+ if (allocator->isReservedGlobalPlacementOperator()) {
+ assert(allocatorArgs.size() == 2);
+ RV = allocatorArgs[1].RV;
+ // TODO: kill any unnecessary computations done for the size
+ // argument.
+ } else {
+ RV = EmitCall(CGM.getTypes().getFunctionInfo(allocatorArgs, allocatorType),
+ CGM.GetAddrOfFunction(allocator), ReturnValueSlot(),
+ allocatorArgs, allocator);
+ }
// Emit a null check on the allocation result if the allocation
// function is allowed to return null (because it has a non-throwing
@@ -1056,7 +1112,8 @@ llvm::Value *CodeGenFunction::EmitCXXNewExpr(const CXXNewExpr *E) {
// If there's an operator delete, enter a cleanup to call it if an
// exception is thrown.
EHScopeStack::stable_iterator operatorDeleteCleanup;
- if (E->getOperatorDelete()) {
+ if (E->getOperatorDelete() &&
+ !E->getOperatorDelete()->isReservedGlobalPlacementOperator()) {
EnterNewDeleteCleanup(*this, E, allocation, allocSize, allocatorArgs);
operatorDeleteCleanup = EHStack.stable_begin();
}
diff --git a/lib/CodeGen/CGExprConstant.cpp b/lib/CodeGen/CGExprConstant.cpp
index 463b913..da37bd5 100644
--- a/lib/CodeGen/CGExprConstant.cpp
+++ b/lib/CodeGen/CGExprConstant.cpp
@@ -352,8 +352,7 @@ bool ConstStructBuilder::Build(InitListExpr *ILE) {
if (IsMsStruct) {
// Zero-length bitfields following non-bitfield members are
// ignored:
- if (CGM.getContext().ZeroBitfieldFollowsNonBitfield((*Field), LastFD) ||
- CGM.getContext().ZeroBitfieldFollowsBitfield((*Field), LastFD)) {
+ if (CGM.getContext().ZeroBitfieldFollowsNonBitfield((*Field), LastFD)) {
--FieldNo;
continue;
}
@@ -611,12 +610,12 @@ public:
return llvm::ConstantPointerNull::get(cast<llvm::PointerType>(destType));
case CK_IntegralCast: {
- bool isSigned = subExpr->getType()->isSignedIntegerType();
+ bool isSigned = subExpr->getType()->isSignedIntegerOrEnumerationType();
return llvm::ConstantExpr::getIntegerCast(C, destType, isSigned);
}
case CK_IntegralToPointer: {
- bool isSigned = subExpr->getType()->isSignedIntegerType();
+ bool isSigned = subExpr->getType()->isSignedIntegerOrEnumerationType();
C = llvm::ConstantExpr::getIntegerCast(C, CGM.IntPtrTy, isSigned);
return llvm::ConstantExpr::getIntToPtr(C, destType);
}
@@ -626,13 +625,13 @@ public:
llvm::Constant::getNullValue(C->getType()));
case CK_IntegralToFloating:
- if (subExpr->getType()->isSignedIntegerType())
+ if (subExpr->getType()->isSignedIntegerOrEnumerationType())
return llvm::ConstantExpr::getSIToFP(C, destType);
else
return llvm::ConstantExpr::getUIToFP(C, destType);
case CK_FloatingToIntegral:
- if (E->getType()->isSignedIntegerType())
+ if (E->getType()->isSignedIntegerOrEnumerationType())
return llvm::ConstantExpr::getFPToSI(C, destType);
else
return llvm::ConstantExpr::getFPToUI(C, destType);
diff --git a/lib/CodeGen/CGExprScalar.cpp b/lib/CodeGen/CGExprScalar.cpp
index 6bcc425..dff7bf4 100644
--- a/lib/CodeGen/CGExprScalar.cpp
+++ b/lib/CodeGen/CGExprScalar.cpp
@@ -400,7 +400,7 @@ public:
// Binary Operators.
Value *EmitMul(const BinOpInfo &Ops) {
- if (Ops.Ty->hasSignedIntegerRepresentation()) {
+ if (Ops.Ty->isSignedIntegerOrEnumerationType()) {
switch (CGF.getContext().getLangOptions().getSignedOverflowBehavior()) {
case LangOptions::SOB_Undefined:
return Builder.CreateNSWMul(Ops.LHS, Ops.RHS, "mul");
@@ -508,6 +508,7 @@ public:
Value *VisitObjCStringLiteral(const ObjCStringLiteral *E) {
return CGF.EmitObjCStringLiteral(E);
}
+ Value *VisitAsTypeExpr(AsTypeExpr *CE);
};
} // end anonymous namespace.
@@ -568,7 +569,7 @@ Value *ScalarExprEmitter::EmitScalarConversion(Value *Src, QualType SrcType,
// First, convert to the correct width so that we control the kind of
// extension.
const llvm::Type *MiddleTy = CGF.IntPtrTy;
- bool InputSigned = SrcType->isSignedIntegerType();
+ bool InputSigned = SrcType->isSignedIntegerOrEnumerationType();
llvm::Value* IntResult =
Builder.CreateIntCast(Src, MiddleTy, InputSigned, "conv");
// Then, cast to pointer.
@@ -610,7 +611,7 @@ Value *ScalarExprEmitter::EmitScalarConversion(Value *Src, QualType SrcType,
// Finally, we have the arithmetic types: real int/float.
if (isa<llvm::IntegerType>(Src->getType())) {
- bool InputSigned = SrcType->isSignedIntegerType();
+ bool InputSigned = SrcType->isSignedIntegerOrEnumerationType();
if (isa<llvm::IntegerType>(DstTy))
return Builder.CreateIntCast(Src, DstTy, InputSigned, "conv");
else if (InputSigned)
@@ -621,7 +622,7 @@ Value *ScalarExprEmitter::EmitScalarConversion(Value *Src, QualType SrcType,
assert(Src->getType()->isFloatingPointTy() && "Unknown real conversion");
if (isa<llvm::IntegerType>(DstTy)) {
- if (DstType->isSignedIntegerType())
+ if (DstType->isSignedIntegerOrEnumerationType())
return Builder.CreateFPToSI(Src, DstTy, "conv");
else
return Builder.CreateFPToUI(Src, DstTy, "conv");
@@ -758,19 +759,13 @@ Value *ScalarExprEmitter::VisitShuffleVectorExpr(ShuffleVectorExpr *E) {
Value* V2 = CGF.EmitScalarExpr(E->getExpr(1));
// Handle vec3 special since the index will be off by one for the RHS.
+ const llvm::VectorType *VTy = cast<llvm::VectorType>(V1->getType());
llvm::SmallVector<llvm::Constant*, 32> indices;
for (unsigned i = 2; i < E->getNumSubExprs(); i++) {
- llvm::Constant *C = cast<llvm::Constant>(CGF.EmitScalarExpr(E->getExpr(i)));
- const llvm::VectorType *VTy = cast<llvm::VectorType>(V1->getType());
- if (VTy->getNumElements() == 3) {
- if (llvm::ConstantInt *CI = dyn_cast<llvm::ConstantInt>(C)) {
- uint64_t cVal = CI->getZExtValue();
- if (cVal > 3) {
- C = llvm::ConstantInt::get(C->getType(), cVal-1);
- }
- }
- }
- indices.push_back(C);
+ unsigned Idx = E->getShuffleMaskIdx(CGF.getContext(), i-2);
+ if (VTy->getNumElements() == 3 && Idx > 3)
+ Idx -= 1;
+ indices.push_back(Builder.getInt32(Idx));
}
Value *SV = llvm::ConstantVector::get(indices);
@@ -813,7 +808,7 @@ Value *ScalarExprEmitter::VisitArraySubscriptExpr(ArraySubscriptExpr *E) {
// integer value.
Value *Base = Visit(E->getBase());
Value *Idx = Visit(E->getIdx());
- bool IdxSigned = E->getIdx()->getType()->isSignedIntegerType();
+ bool IdxSigned = E->getIdx()->getType()->isSignedIntegerOrEnumerationType();
Idx = Builder.CreateIntCast(Idx, CGF.Int32Ty, IdxSigned, "vecidxcast");
return Builder.CreateExtractElement(Base, Idx, "vecext");
}
@@ -1142,7 +1137,7 @@ Value *ScalarExprEmitter::EmitCastExpr(CastExpr *CE) {
// First, convert to the correct width so that we control the kind of
// extension.
const llvm::Type *MiddleTy = CGF.IntPtrTy;
- bool InputSigned = E->getType()->isSignedIntegerType();
+ bool InputSigned = E->getType()->isSignedIntegerOrEnumerationType();
llvm::Value* IntResult =
Builder.CreateIntCast(Src, MiddleTy, InputSigned, "conv");
@@ -1285,7 +1280,7 @@ ScalarExprEmitter::EmitScalarPrePostIncDec(const UnaryOperator *E, LValue LV,
// Note that signed integer inc/dec with width less than int can't
// overflow because of promotion rules; we're just eliding a few steps here.
- if (type->isSignedIntegerType() &&
+ if (type->isSignedIntegerOrEnumerationType() &&
value->getType()->getPrimitiveSizeInBits() >=
CGF.CGM.IntTy->getBitWidth())
value = EmitAddConsiderOverflowBehavior(E, value, amt, isInc);
@@ -1333,10 +1328,7 @@ ScalarExprEmitter::EmitScalarPrePostIncDec(const UnaryOperator *E, LValue LV,
if (type->hasIntegerRepresentation()) {
llvm::Value *amt = llvm::ConstantInt::get(value->getType(), amount);
- if (type->hasSignedIntegerRepresentation())
- value = EmitAddConsiderOverflowBehavior(E, value, amt, isInc);
- else
- value = Builder.CreateAdd(value, amt, isInc ? "inc" : "dec");
+ value = Builder.CreateAdd(value, amt, isInc ? "inc" : "dec");
} else {
value = Builder.CreateFAdd(
value,
@@ -1447,7 +1439,7 @@ Value *ScalarExprEmitter::VisitOffsetOfExpr(OffsetOfExpr *E) {
// Compute the index
Expr *IdxExpr = E->getIndexExpr(ON.getArrayExprIndex());
llvm::Value* Idx = CGF.EmitScalarExpr(IdxExpr);
- bool IdxSigned = IdxExpr->getType()->isSignedIntegerType();
+ bool IdxSigned = IdxExpr->getType()->isSignedIntegerOrEnumerationType();
Idx = Builder.CreateIntCast(Idx, ResultType, IdxSigned, "conv");
// Save the element type
@@ -1797,9 +1789,7 @@ Value *ScalarExprEmitter::EmitOverflowCheckedBinOp(const BinOpInfo &Ops) {
// Get the overflow handler.
const llvm::Type *Int8Ty = llvm::Type::getInt8Ty(VMContext);
- std::vector<const llvm::Type*> argTypes;
- argTypes.push_back(CGF.Int64Ty); argTypes.push_back(CGF.Int64Ty);
- argTypes.push_back(Int8Ty); argTypes.push_back(Int8Ty);
+ const llvm::Type *argTypes[] = { CGF.Int64Ty, CGF.Int64Ty, Int8Ty, Int8Ty };
llvm::FunctionType *handlerTy =
llvm::FunctionType::get(CGF.Int64Ty, argTypes, true);
llvm::Value *handler = CGF.CGM.CreateRuntimeFunction(handlerTy, *handlerName);
@@ -1829,7 +1819,7 @@ Value *ScalarExprEmitter::EmitOverflowCheckedBinOp(const BinOpInfo &Ops) {
Value *ScalarExprEmitter::EmitAdd(const BinOpInfo &Ops) {
if (!Ops.Ty->isAnyPointerType()) {
- if (Ops.Ty->hasSignedIntegerRepresentation()) {
+ if (Ops.Ty->isSignedIntegerOrEnumerationType()) {
switch (CGF.getContext().getLangOptions().getSignedOverflowBehavior()) {
case LangOptions::SOB_Undefined:
return Builder.CreateNSWAdd(Ops.LHS, Ops.RHS, "add");
@@ -1879,7 +1869,7 @@ Value *ScalarExprEmitter::EmitAdd(const BinOpInfo &Ops) {
// Zero or sign extend the pointer value based on whether the index is
// signed or not.
const llvm::Type *IdxType = CGF.IntPtrTy;
- if (IdxExp->getType()->isSignedIntegerType())
+ if (IdxExp->getType()->isSignedIntegerOrEnumerationType())
Idx = Builder.CreateSExt(Idx, IdxType, "idx.ext");
else
Idx = Builder.CreateZExt(Idx, IdxType, "idx.ext");
@@ -1914,7 +1904,7 @@ Value *ScalarExprEmitter::EmitAdd(const BinOpInfo &Ops) {
Value *ScalarExprEmitter::EmitSub(const BinOpInfo &Ops) {
if (!isa<llvm::PointerType>(Ops.LHS->getType())) {
- if (Ops.Ty->hasSignedIntegerRepresentation()) {
+ if (Ops.Ty->isSignedIntegerOrEnumerationType()) {
switch (CGF.getContext().getLangOptions().getSignedOverflowBehavior()) {
case LangOptions::SOB_Undefined:
return Builder.CreateNSWSub(Ops.LHS, Ops.RHS, "sub");
@@ -1954,7 +1944,7 @@ Value *ScalarExprEmitter::EmitSub(const BinOpInfo &Ops) {
// Zero or sign extend the pointer value based on whether the index is
// signed or not.
const llvm::Type *IdxType = CGF.IntPtrTy;
- if (BinOp->getRHS()->getType()->isSignedIntegerType())
+ if (BinOp->getRHS()->getType()->isSignedIntegerOrEnumerationType())
Idx = Builder.CreateSExt(Idx, IdxType, "idx.ext");
else
Idx = Builder.CreateZExt(Idx, IdxType, "idx.ext");
@@ -2556,6 +2546,56 @@ Value *ScalarExprEmitter::VisitBlockExpr(const BlockExpr *block) {
return CGF.EmitBlockLiteral(block);
}
+Value *ScalarExprEmitter::VisitAsTypeExpr(AsTypeExpr *E) {
+ Value *Src = CGF.EmitScalarExpr(E->getSrcExpr());
+ const llvm::Type * DstTy = ConvertType(E->getDstType());
+
+ // Going from vec4->vec3 or vec3->vec4 is a special case and requires
+ // a shuffle vector instead of a bitcast.
+ const llvm::Type *SrcTy = Src->getType();
+ if (isa<llvm::VectorType>(DstTy) && isa<llvm::VectorType>(SrcTy)) {
+ unsigned numElementsDst = cast<llvm::VectorType>(DstTy)->getNumElements();
+ unsigned numElementsSrc = cast<llvm::VectorType>(SrcTy)->getNumElements();
+ if ((numElementsDst == 3 && numElementsSrc == 4)
+ || (numElementsDst == 4 && numElementsSrc == 3)) {
+
+
+ // In the case of going from int4->float3, a bitcast is needed before
+ // doing a shuffle.
+ const llvm::Type *srcElemTy =
+ cast<llvm::VectorType>(SrcTy)->getElementType();
+ const llvm::Type *dstElemTy =
+ cast<llvm::VectorType>(DstTy)->getElementType();
+
+ if ((srcElemTy->isIntegerTy() && dstElemTy->isFloatTy())
+ || (srcElemTy->isFloatTy() && dstElemTy->isIntegerTy())) {
+ // Create a float type of the same size as the source or destination.
+ const llvm::VectorType *newSrcTy = llvm::VectorType::get(dstElemTy,
+ numElementsSrc);
+
+ Src = Builder.CreateBitCast(Src, newSrcTy, "astypeCast");
+ }
+
+ llvm::Value *UnV = llvm::UndefValue::get(Src->getType());
+
+ llvm::SmallVector<llvm::Constant*, 3> Args;
+ Args.push_back(Builder.getInt32(0));
+ Args.push_back(Builder.getInt32(1));
+ Args.push_back(Builder.getInt32(2));
+
+ if (numElementsDst == 4)
+ Args.push_back(llvm::UndefValue::get(
+ llvm::Type::getInt32Ty(CGF.getLLVMContext())));
+
+ llvm::Constant *Mask = llvm::ConstantVector::get(Args);
+
+ return Builder.CreateShuffleVector(Src, UnV, Mask, "astype");
+ }
+ }
+
+ return Builder.CreateBitCast(Src, DstTy, "astype");
+}
+
//===----------------------------------------------------------------------===//
// Entry Point into this File
//===----------------------------------------------------------------------===//
diff --git a/lib/CodeGen/CGObjC.cpp b/lib/CodeGen/CGObjC.cpp
index 5b0d41e..fa42cd1 100644
--- a/lib/CodeGen/CGObjC.cpp
+++ b/lib/CodeGen/CGObjC.cpp
@@ -47,6 +47,23 @@ llvm::Value *CodeGenFunction::EmitObjCProtocolExpr(const ObjCProtocolExpr *E) {
return CGM.getObjCRuntime().GenerateProtocolRef(Builder, E->getProtocol());
}
+/// \brief Adjust the type of the result of an Objective-C message send
+/// expression when the method has a related result type.
+static RValue AdjustRelatedResultType(CodeGenFunction &CGF,
+ const Expr *E,
+ const ObjCMethodDecl *Method,
+ RValue Result) {
+ if (!Method)
+ return Result;
+ if (!Method->hasRelatedResultType() ||
+ CGF.getContext().hasSameType(E->getType(), Method->getResultType()) ||
+ !Result.isScalar())
+ return Result;
+
+ // We have applied a related result type. Cast the rvalue appropriately.
+ return RValue::get(CGF.Builder.CreateBitCast(Result.getScalarVal(),
+ CGF.ConvertType(E->getType())));
+}
RValue CodeGenFunction::EmitObjCMessageExpr(const ObjCMessageExpr *E,
ReturnValueSlot Return) {
@@ -59,15 +76,17 @@ RValue CodeGenFunction::EmitObjCMessageExpr(const ObjCMessageExpr *E,
bool isClassMessage = false;
ObjCInterfaceDecl *OID = 0;
// Find the receiver
+ QualType ReceiverType;
llvm::Value *Receiver = 0;
switch (E->getReceiverKind()) {
case ObjCMessageExpr::Instance:
Receiver = EmitScalarExpr(E->getInstanceReceiver());
+ ReceiverType = E->getInstanceReceiver()->getType();
break;
case ObjCMessageExpr::Class: {
- const ObjCObjectType *ObjTy
- = E->getClassReceiver()->getAs<ObjCObjectType>();
+ ReceiverType = E->getClassReceiver();
+ const ObjCObjectType *ObjTy = ReceiverType->getAs<ObjCObjectType>();
assert(ObjTy && "Invalid Objective-C class message send");
OID = ObjTy->getInterface();
assert(OID && "Invalid Objective-C class message send");
@@ -77,11 +96,13 @@ RValue CodeGenFunction::EmitObjCMessageExpr(const ObjCMessageExpr *E,
}
case ObjCMessageExpr::SuperInstance:
+ ReceiverType = E->getSuperType();
Receiver = LoadObjCSelf();
isSuperMessage = true;
break;
case ObjCMessageExpr::SuperClass:
+ ReceiverType = E->getSuperType();
Receiver = LoadObjCSelf();
isSuperMessage = true;
isClassMessage = true;
@@ -94,31 +115,35 @@ RValue CodeGenFunction::EmitObjCMessageExpr(const ObjCMessageExpr *E,
QualType ResultType =
E->getMethodDecl() ? E->getMethodDecl()->getResultType() : E->getType();
+ RValue result;
if (isSuperMessage) {
// 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, Return, ResultType,
- E->getSelector(),
- OMD->getClassInterface(),
- isCategoryImpl,
- Receiver,
- isClassMessage,
- Args,
- E->getMethodDecl());
+ result = Runtime.GenerateMessageSendSuper(*this, Return, ResultType,
+ E->getSelector(),
+ OMD->getClassInterface(),
+ isCategoryImpl,
+ Receiver,
+ isClassMessage,
+ Args,
+ E->getMethodDecl());
+ } else {
+ result = Runtime.GenerateMessageSend(*this, Return, ResultType,
+ E->getSelector(),
+ Receiver, Args, OID,
+ E->getMethodDecl());
}
-
- return Runtime.GenerateMessageSend(*this, Return, ResultType,
- E->getSelector(),
- Receiver, Args, OID,
- E->getMethodDecl());
+
+ return AdjustRelatedResultType(*this, E, E->getMethodDecl(), result);
}
/// StartObjCMethod - Begin emission of an ObjCMethod. This generates
/// the LLVM function and sets the other context used by
/// CodeGenFunction.
void CodeGenFunction::StartObjCMethod(const ObjCMethodDecl *OMD,
- const ObjCContainerDecl *CD) {
+ const ObjCContainerDecl *CD,
+ SourceLocation StartLoc) {
FunctionArgList args;
// Check if we should generate debug info for this method.
if (CGM.getModuleDebugInfo() && !OMD->hasAttr<NoDebugAttr>())
@@ -138,7 +163,7 @@ void CodeGenFunction::StartObjCMethod(const ObjCMethodDecl *OMD,
CurGD = OMD;
- StartFunction(OMD, OMD->getResultType(), Fn, FI, args, OMD->getLocStart());
+ StartFunction(OMD, OMD->getResultType(), Fn, FI, args, StartLoc);
}
void CodeGenFunction::GenerateObjCGetterBody(ObjCIvarDecl *Ivar,
@@ -151,16 +176,14 @@ void CodeGenFunction::GenerateObjCGetterBody(ObjCIvarDecl *Ivar,
// objc_copyStruct (ReturnValue, &structIvar,
// sizeof (Type of Ivar), isAtomic, false);
CallArgList Args;
- RValue RV = RValue::get(Builder.CreateBitCast(ReturnValue,
- Types.ConvertType(getContext().VoidPtrTy)));
+ RValue RV = RValue::get(Builder.CreateBitCast(ReturnValue, VoidPtrTy));
Args.add(RV, getContext().VoidPtrTy);
- RV = RValue::get(Builder.CreateBitCast(LV.getAddress(),
- Types.ConvertType(getContext().VoidPtrTy)));
+ RV = RValue::get(Builder.CreateBitCast(LV.getAddress(), VoidPtrTy));
Args.add(RV, getContext().VoidPtrTy);
// sizeof (Type of Ivar)
CharUnits Size = getContext().getTypeSizeInChars(Ivar->getType());
llvm::Value *SizeVal =
- llvm::ConstantInt::get(Types.ConvertType(getContext().LongTy),
+ llvm::ConstantInt::get(Types.ConvertType(getContext().LongTy),
Size.getQuantity());
Args.add(RValue::get(SizeVal), getContext().LongTy);
llvm::Value *isAtomic =
@@ -179,7 +202,7 @@ void CodeGenFunction::GenerateObjCGetterBody(ObjCIvarDecl *Ivar,
/// Generate an Objective-C method. An Objective-C method is a C function with
/// its pointer, name, and types registered in the class struture.
void CodeGenFunction::GenerateObjCMethod(const ObjCMethodDecl *OMD) {
- StartObjCMethod(OMD, OMD->getClassInterface());
+ StartObjCMethod(OMD, OMD->getClassInterface(), OMD->getLocStart());
EmitStmt(OMD->getBody());
FinishFunction(OMD->getBodyRBrace());
}
@@ -199,7 +222,7 @@ void CodeGenFunction::GenerateObjCGetter(ObjCImplementationDecl *IMP,
!(PD->getPropertyAttributes() & ObjCPropertyDecl::OBJC_PR_nonatomic);
ObjCMethodDecl *OMD = PD->getGetterMethodDecl();
assert(OMD && "Invalid call to generate getter (empty method)");
- StartObjCMethod(OMD, IMP->getClassInterface());
+ StartObjCMethod(OMD, IMP->getClassInterface(), PID->getLocStart());
// Determine if we should use an objc_getProperty call for
// this. Non-atomic properties are directly evaluated.
@@ -292,7 +315,7 @@ void CodeGenFunction::GenerateObjCGetter(ObjCImplementationDecl *IMP,
const CXXRecordDecl *classDecl = IVART->getAsCXXRecordDecl();
if (PID->getGetterCXXConstructor() &&
- classDecl && !classDecl->hasTrivialConstructor()) {
+ classDecl && !classDecl->hasTrivialDefaultConstructor()) {
ReturnStmt *Stmt =
new (getContext()) ReturnStmt(SourceLocation(),
PID->getGetterCXXConstructor(),
@@ -398,7 +421,7 @@ void CodeGenFunction::GenerateObjCSetter(ObjCImplementationDecl *IMP,
const ObjCPropertyDecl *PD = PID->getPropertyDecl();
ObjCMethodDecl *OMD = PD->getSetterMethodDecl();
assert(OMD && "Invalid call to generate setter (empty method)");
- StartObjCMethod(OMD, IMP->getClassInterface());
+ StartObjCMethod(OMD, IMP->getClassInterface(), PID->getLocStart());
const llvm::Triple &Triple = getContext().Target.getTriple();
QualType IVART = Ivar->getType();
bool IsCopy = PD->getSetterKind() == ObjCPropertyDecl::Copy;
@@ -496,7 +519,7 @@ void CodeGenFunction::GenerateObjCSetter(ObjCImplementationDecl *IMP,
}
else {
// FIXME: Find a clean way to avoid AST node creation.
- SourceLocation Loc = PD->getLocation();
+ SourceLocation Loc = PID->getLocStart();
ValueDecl *Self = OMD->getSelfDecl();
ObjCIvarDecl *Ivar = PID->getPropertyIvarDecl();
DeclRefExpr Base(Self, Self->getType(), VK_RValue, Loc);
@@ -618,7 +641,7 @@ void CodeGenFunction::GenerateObjCCtorDtorMethod(ObjCImplementationDecl *IMP,
ObjCMethodDecl *MD,
bool ctor) {
MD->createImplicitParams(CGM.getContext(), IMP->getClassInterface());
- StartObjCMethod(MD, IMP->getClassInterface());
+ StartObjCMethod(MD, IMP->getClassInterface(), MD->getLocStart());
// Emit .cxx_construct.
if (ctor) {
@@ -712,26 +735,31 @@ RValue CodeGenFunction::EmitLoadOfPropertyRefLValue(LValue LV,
const ObjCPropertyRefExpr *E = LV.getPropertyRefExpr();
QualType ResultType = E->getGetterResultType();
Selector S;
+ const ObjCMethodDecl *method;
if (E->isExplicitProperty()) {
const ObjCPropertyDecl *Property = E->getExplicitProperty();
S = Property->getGetterName();
+ method = Property->getGetterMethodDecl();
} else {
- const ObjCMethodDecl *Getter = E->getImplicitPropertyGetter();
- S = Getter->getSelector();
+ method = E->getImplicitPropertyGetter();
+ S = method->getSelector();
}
llvm::Value *Receiver = LV.getPropertyRefBaseAddr();
// Accesses to 'super' follow a different code path.
if (E->isSuperReceiver())
- return GenerateMessageSendSuper(*this, Return, ResultType,
- S, Receiver, CallArgList());
-
+ return AdjustRelatedResultType(*this, E, method,
+ GenerateMessageSendSuper(*this, Return,
+ ResultType,
+ S, Receiver,
+ CallArgList()));
const ObjCInterfaceDecl *ReceiverClass
= (E->isClassReceiver() ? E->getClassReceiver() : 0);
- return CGM.getObjCRuntime().
- GenerateMessageSend(*this, Return, ResultType, S,
- Receiver, CallArgList(), ReceiverClass);
+ return AdjustRelatedResultType(*this, E, method,
+ CGM.getObjCRuntime().
+ GenerateMessageSend(*this, Return, ResultType, S,
+ Receiver, CallArgList(), ReceiverClass));
}
void CodeGenFunction::EmitStoreThroughPropertyRefLValue(RValue Src,
diff --git a/lib/CodeGen/CGObjCGNU.cpp b/lib/CodeGen/CGObjCGNU.cpp
index c4dc4c4..f0993c5 100644
--- a/lib/CodeGen/CGObjCGNU.cpp
+++ b/lib/CodeGen/CGObjCGNU.cpp
@@ -52,7 +52,7 @@ class LazyRuntimeFunction {
CodeGenModule *CGM;
std::vector<const llvm::Type*> ArgTys;
const char *FunctionName;
- llvm::Function *Function;
+ llvm::Constant *Function;
public:
/// Constructor leaves this class uninitialized, because it is intended to
/// be used as a field in another class and not all of the types that are
@@ -78,7 +78,7 @@ class LazyRuntimeFunction {
}
/// Overloaded cast operator, allows the class to be implicitly cast to an
/// LLVM constant.
- operator llvm::Function*() {
+ operator llvm::Constant*() {
if (!Function) {
if (0 == FunctionName) return 0;
// We put the return type on the end of the vector, so pop it back off
@@ -86,13 +86,17 @@ class LazyRuntimeFunction {
ArgTys.pop_back();
llvm::FunctionType *FTy = llvm::FunctionType::get(RetTy, ArgTys, false);
Function =
- cast<llvm::Function>(CGM->CreateRuntimeFunction(FTy, FunctionName));
+ cast<llvm::Constant>(CGM->CreateRuntimeFunction(FTy, FunctionName));
// We won't need to use the types again, so we may as well clean up the
// vector now
ArgTys.resize(0);
}
return Function;
}
+ operator llvm::Function*() {
+ return cast<llvm::Function>((llvm::Constant*)*this);
+ }
+
};
@@ -314,7 +318,7 @@ private:
/// The version of the runtime that this class targets. Must match the
/// version in the runtime.
- const int RuntimeVersion;
+ int RuntimeVersion;
/// The version of the protocol class. Used to differentiate between ObjC1
/// and ObjC2 protocols. Objective-C 1 protocols can not contain optional
/// components and can not contain declared properties. We always emit
@@ -444,10 +448,10 @@ public:
const ObjCProtocolDecl *PD);
virtual void GenerateProtocol(const ObjCProtocolDecl *PD);
virtual llvm::Function *ModuleInitFunction();
- virtual llvm::Function *GetPropertyGetFunction();
- virtual llvm::Function *GetPropertySetFunction();
- virtual llvm::Function *GetSetStructFunction();
- virtual llvm::Function *GetGetStructFunction();
+ virtual llvm::Constant *GetPropertyGetFunction();
+ virtual llvm::Constant *GetPropertySetFunction();
+ virtual llvm::Constant *GetSetStructFunction();
+ virtual llvm::Constant *GetGetStructFunction();
virtual llvm::Constant *EnumerationMutationFunction();
virtual void EmitTryStmt(CodeGenFunction &CGF,
@@ -484,6 +488,10 @@ public:
const CGBlockInfo &blockInfo) {
return NULLPtr;
}
+
+ virtual llvm::GlobalVariable *GetClassGlobal(const std::string &Name) {
+ return 0;
+ }
};
/// Class representing the legacy GCC Objective-C ABI. This is the default when
/// -fobjc-nonfragile-abi is not specified.
@@ -654,7 +662,6 @@ CGObjCGNU::CGObjCGNU(CodeGenModule &cgm, unsigned runtimeABIVersion,
: CGM(cgm), TheModule(CGM.getModule()), VMContext(cgm.getLLVMContext()),
ClassPtrAlias(0), MetaClassPtrAlias(0), RuntimeVersion(runtimeABIVersion),
ProtocolVersion(protocolClassVersion) {
-
msgSendMDKind = VMContext.getMDKindID("GNUObjCMessageSend");
@@ -729,14 +736,16 @@ CGObjCGNU::CGObjCGNU(CodeGenModule &cgm, unsigned runtimeABIVersion,
PtrDiffTy, BoolTy, BoolTy, NULL);
// IMP type
- std::vector<const llvm::Type*> IMPArgs;
- IMPArgs.push_back(IdTy);
- IMPArgs.push_back(SelectorTy);
+ const llvm::Type *IMPArgs[] = { IdTy, SelectorTy };
IMPTy = llvm::PointerType::getUnqual(llvm::FunctionType::get(IdTy, IMPArgs,
true));
// Don't bother initialising the GC stuff unless we're compiling in GC mode
if (CGM.getLangOptions().getGCMode() != LangOptions::NonGC) {
+ // This is a bit of an hack. We should sort this out by having a proper
+ // CGObjCGNUstep subclass for GC, but we may want to really support the old
+ // ABI and GC added in ObjectiveC2.framework, so we fudge it a bit for now
+ RuntimeVersion = 10;
// Get selectors needed in GC mode
RetainSel = GetNullarySelector("retain", CGM.getContext());
ReleaseSel = GetNullarySelector("release", CGM.getContext());
@@ -775,11 +784,8 @@ llvm::Value *CGObjCGNU::GetClass(CGBuilderTy &Builder,
EmitClassRef(OID->getNameAsString());
ClassName = Builder.CreateStructGEP(ClassName, 0);
- std::vector<const llvm::Type*> Params(1, PtrToInt8Ty);
llvm::Constant *ClassLookupFn =
- CGM.CreateRuntimeFunction(llvm::FunctionType::get(IdTy,
- Params,
- true),
+ CGM.CreateRuntimeFunction(llvm::FunctionType::get(IdTy, PtrToInt8Ty, true),
"objc_lookup_class");
return Builder.CreateCall(ClassLookupFn, ClassName);
}
@@ -945,16 +951,17 @@ CGObjCGNU::GenerateMessageSendSuper(CodeGenFunction &CGF,
bool IsClassMessage,
const CallArgList &CallArgs,
const ObjCMethodDecl *Method) {
- if (CGM.getLangOptions().getGCMode() != LangOptions::NonGC) {
+ CGBuilderTy &Builder = CGF.Builder;
+ if (CGM.getLangOptions().getGCMode() == LangOptions::GCOnly) {
if (Sel == RetainSel || Sel == AutoreleaseSel) {
- return RValue::get(Receiver);
+ return RValue::get(EnforceType(Builder, Receiver,
+ CGM.getTypes().ConvertType(ResultType)));
}
if (Sel == ReleaseSel) {
return RValue::get(0);
}
}
- CGBuilderTy &Builder = CGF.Builder;
llvm::Value *cmd = GetSelector(Builder, Sel);
@@ -971,14 +978,12 @@ CGObjCGNU::GenerateMessageSendSuper(CodeGenFunction &CGF,
llvm::Value *ReceiverClass = 0;
if (isCategoryImpl) {
llvm::Constant *classLookupFunction = 0;
- std::vector<const llvm::Type*> Params;
- Params.push_back(PtrTy);
if (IsClassMessage) {
classLookupFunction = CGM.CreateRuntimeFunction(llvm::FunctionType::get(
- IdTy, Params, true), "objc_get_meta_class");
+ IdTy, PtrTy, true), "objc_get_meta_class");
} else {
classLookupFunction = CGM.CreateRuntimeFunction(llvm::FunctionType::get(
- IdTy, Params, true), "objc_get_class");
+ IdTy, PtrTy, true), "objc_get_class");
}
ReceiverClass = Builder.CreateCall(classLookupFunction,
MakeConstantString(Class->getNameAsString()));
@@ -1052,18 +1057,19 @@ CGObjCGNU::GenerateMessageSend(CodeGenFunction &CGF,
const CallArgList &CallArgs,
const ObjCInterfaceDecl *Class,
const ObjCMethodDecl *Method) {
+ CGBuilderTy &Builder = CGF.Builder;
+
// Strip out message sends to retain / release in GC mode
- if (CGM.getLangOptions().getGCMode() != LangOptions::NonGC) {
+ if (CGM.getLangOptions().getGCMode() == LangOptions::GCOnly) {
if (Sel == RetainSel || Sel == AutoreleaseSel) {
- return RValue::get(Receiver);
+ return RValue::get(EnforceType(Builder, Receiver,
+ CGM.getTypes().ConvertType(ResultType)));
}
if (Sel == ReleaseSel) {
return RValue::get(0);
}
}
- CGBuilderTy &Builder = CGF.Builder;
-
// If the return type is something that goes in an integer register, the
// runtime will handle 0 returns. For other cases, we fill in the 0 value
// ourselves.
@@ -2127,7 +2133,9 @@ llvm::Function *CGObjCGNU::ModuleInitFunction() {
// The symbol table is contained in a module which has some version-checking
// constants
llvm::StructType * ModuleTy = llvm::StructType::get(VMContext, LongTy, LongTy,
- PtrToInt8Ty, llvm::PointerType::getUnqual(SymTabTy), NULL);
+ PtrToInt8Ty, llvm::PointerType::getUnqual(SymTabTy),
+ (CGM.getLangOptions().getGCMode() == LangOptions::NonGC) ? NULL : IntTy,
+ NULL);
Elements.clear();
// Runtime version, used for ABI compatibility checking.
Elements.push_back(llvm::ConstantInt::get(LongTy, RuntimeVersion));
@@ -2144,8 +2152,17 @@ llvm::Function *CGObjCGNU::ModuleInitFunction() {
std::string path =
std::string(mainFile->getDir()->getName()) + '/' + mainFile->getName();
Elements.push_back(MakeConstantString(path, ".objc_source_file_name"));
-
Elements.push_back(SymTab);
+
+ switch (CGM.getLangOptions().getGCMode()) {
+ case LangOptions::GCOnly:
+ Elements.push_back(llvm::ConstantInt::get(IntTy, 2));
+ case LangOptions::NonGC:
+ break;
+ case LangOptions::HybridGC:
+ Elements.push_back(llvm::ConstantInt::get(IntTy, 1));
+ }
+
llvm::Value *Module = MakeGlobal(ModuleTy, Elements);
// Create the load function calling the runtime entry point with the module
@@ -2159,10 +2176,10 @@ llvm::Function *CGObjCGNU::ModuleInitFunction() {
CGBuilderTy Builder(VMContext);
Builder.SetInsertPoint(EntryBB);
- std::vector<const llvm::Type*> Params(1,
- llvm::PointerType::getUnqual(ModuleTy));
- llvm::Value *Register = CGM.CreateRuntimeFunction(llvm::FunctionType::get(
- llvm::Type::getVoidTy(VMContext), Params, true), "__objc_exec_class");
+ llvm::FunctionType *FT =
+ llvm::FunctionType::get(Builder.getVoidTy(),
+ llvm::PointerType::getUnqual(ModuleTy), true);
+ llvm::Value *Register = CGM.CreateRuntimeFunction(FT, "__objc_exec_class");
Builder.CreateCall(Register, Module);
Builder.CreateRetVoid();
@@ -2192,18 +2209,18 @@ llvm::Function *CGObjCGNU::GenerateMethod(const ObjCMethodDecl *OMD,
return Method;
}
-llvm::Function *CGObjCGNU::GetPropertyGetFunction() {
+llvm::Constant *CGObjCGNU::GetPropertyGetFunction() {
return GetPropertyFn;
}
-llvm::Function *CGObjCGNU::GetPropertySetFunction() {
+llvm::Constant *CGObjCGNU::GetPropertySetFunction() {
return SetPropertyFn;
}
-llvm::Function *CGObjCGNU::GetGetStructFunction() {
+llvm::Constant *CGObjCGNU::GetGetStructFunction() {
return GetStructPropertyFn;
}
-llvm::Function *CGObjCGNU::GetSetStructFunction() {
+llvm::Constant *CGObjCGNU::GetSetStructFunction() {
return SetStructPropertyFn;
}
@@ -2273,7 +2290,7 @@ void CGObjCGNU::EmitThrowStmt(CodeGenFunction &CGF,
llvm::Value * CGObjCGNU::EmitObjCWeakRead(CodeGenFunction &CGF,
llvm::Value *AddrWeakObj) {
CGBuilderTy B = CGF.Builder;
- AddrWeakObj = EnforceType(B, AddrWeakObj, IdTy);
+ AddrWeakObj = EnforceType(B, AddrWeakObj, PtrToIdTy);
return B.CreateCall(WeakReadFn, AddrWeakObj);
}
@@ -2303,7 +2320,7 @@ void CGObjCGNU::EmitObjCIvarAssign(CodeGenFunction &CGF,
llvm::Value *ivarOffset) {
CGBuilderTy B = CGF.Builder;
src = EnforceType(B, src, IdTy);
- dst = EnforceType(B, dst, PtrToIdTy);
+ dst = EnforceType(B, dst, IdTy);
B.CreateCall3(IvarAssignFn, src, dst, ivarOffset);
}
@@ -2320,8 +2337,8 @@ void CGObjCGNU::EmitGCMemmoveCollectable(CodeGenFunction &CGF,
llvm::Value *SrcPtr,
llvm::Value *Size) {
CGBuilderTy B = CGF.Builder;
- DestPtr = EnforceType(B, DestPtr, IdTy);
- SrcPtr = EnforceType(B, SrcPtr, PtrToIdTy);
+ DestPtr = EnforceType(B, DestPtr, PtrTy);
+ SrcPtr = EnforceType(B, SrcPtr, PtrTy);
B.CreateCall3(MemMoveFn, DestPtr, SrcPtr, Size);
}
diff --git a/lib/CodeGen/CGObjCMac.cpp b/lib/CodeGen/CGObjCMac.cpp
index 2b1cfe3..8c3e9a3 100644
--- a/lib/CodeGen/CGObjCMac.cpp
+++ b/lib/CodeGen/CGObjCMac.cpp
@@ -43,18 +43,6 @@ using namespace clang;
using namespace CodeGen;
-static void EmitNullReturnInitialization(CodeGenFunction &CGF,
- ReturnValueSlot &returnSlot,
- QualType resultType) {
- // Force the return slot to exist.
- if (!returnSlot.getValue())
- returnSlot = ReturnValueSlot(CGF.CreateMemTemp(resultType), false);
- CGF.EmitNullInitialization(returnSlot.getValue(), resultType);
-}
-
-
-///
-
namespace {
typedef std::vector<llvm::Constant*> ConstantVector;
@@ -67,89 +55,89 @@ protected:
llvm::LLVMContext &VMContext;
private:
+ // The types of these functions don't really matter because we
+ // should always bitcast before calling them.
+
+ /// id objc_msgSend (id, SEL, ...)
+ ///
+ /// The default messenger, used for sends whose ABI is unchanged from
+ /// the all-integer/pointer case.
llvm::Constant *getMessageSendFn() const {
- // id objc_msgSend (id, SEL, ...)
- std::vector<const llvm::Type*> Params;
- Params.push_back(ObjectPtrTy);
- Params.push_back(SelectorPtrTy);
- return
- CGM.CreateRuntimeFunction(llvm::FunctionType::get(ObjectPtrTy,
- Params, true),
- "objc_msgSend");
+ const llvm::Type *params[] = { ObjectPtrTy, SelectorPtrTy };
+ return CGM.CreateRuntimeFunction(llvm::FunctionType::get(ObjectPtrTy,
+ params, true),
+ "objc_msgSend");
}
+ /// void objc_msgSend_stret (id, SEL, ...)
+ ///
+ /// The messenger used when the return value is an aggregate returned
+ /// by indirect reference in the first argument, and therefore the
+ /// self and selector parameters are shifted over by one.
llvm::Constant *getMessageSendStretFn() const {
- // id objc_msgSend_stret (id, SEL, ...)
- std::vector<const llvm::Type*> Params;
- Params.push_back(ObjectPtrTy);
- Params.push_back(SelectorPtrTy);
- return
- CGM.CreateRuntimeFunction(llvm::FunctionType::get(llvm::Type::getVoidTy(VMContext),
- Params, true),
- "objc_msgSend_stret");
+ const llvm::Type *params[] = { ObjectPtrTy, SelectorPtrTy };
+ return CGM.CreateRuntimeFunction(llvm::FunctionType::get(CGM.VoidTy,
+ params, true),
+ "objc_msgSend_stret");
}
+ /// [double | long double] objc_msgSend_fpret(id self, SEL op, ...)
+ ///
+ /// The messenger used when the return value is returned on the x87
+ /// floating-point stack; without a special entrypoint, the nil case
+ /// would be unbalanced.
llvm::Constant *getMessageSendFpretFn() const {
- // FIXME: This should be long double on x86_64?
- // [double | long double] objc_msgSend_fpret(id self, SEL op, ...)
- std::vector<const llvm::Type*> Params;
- Params.push_back(ObjectPtrTy);
- Params.push_back(SelectorPtrTy);
- return
- CGM.CreateRuntimeFunction(llvm::FunctionType::get(
+ const llvm::Type *params[] = { ObjectPtrTy, SelectorPtrTy };
+ return CGM.CreateRuntimeFunction(llvm::FunctionType::get(
llvm::Type::getDoubleTy(VMContext),
- Params,
- true),
- "objc_msgSend_fpret");
+ params, true),
+ "objc_msgSend_fpret");
}
+ /// id objc_msgSendSuper(struct objc_super *super, SEL op, ...)
+ ///
+ /// The messenger used for super calls, which have different dispatch
+ /// semantics. The class passed is the superclass of the current
+ /// class.
llvm::Constant *getMessageSendSuperFn() const {
- // id objc_msgSendSuper(struct objc_super *super, SEL op, ...)
- const char *SuperName = "objc_msgSendSuper";
- std::vector<const llvm::Type*> Params;
- Params.push_back(SuperPtrTy);
- Params.push_back(SelectorPtrTy);
+ const llvm::Type *params[] = { SuperPtrTy, SelectorPtrTy };
return CGM.CreateRuntimeFunction(llvm::FunctionType::get(ObjectPtrTy,
- Params, true),
- SuperName);
+ params, true),
+ "objc_msgSendSuper");
}
+ /// id objc_msgSendSuper2(struct objc_super *super, SEL op, ...)
+ ///
+ /// A slightly different messenger used for super calls. The class
+ /// passed is the current class.
llvm::Constant *getMessageSendSuperFn2() const {
- // id objc_msgSendSuper2(struct objc_super *super, SEL op, ...)
- const char *SuperName = "objc_msgSendSuper2";
- std::vector<const llvm::Type*> Params;
- Params.push_back(SuperPtrTy);
- Params.push_back(SelectorPtrTy);
+ const llvm::Type *params[] = { SuperPtrTy, SelectorPtrTy };
return CGM.CreateRuntimeFunction(llvm::FunctionType::get(ObjectPtrTy,
- Params, true),
- SuperName);
+ params, true),
+ "objc_msgSendSuper2");
}
+ /// void objc_msgSendSuper_stret(void *stretAddr, struct objc_super *super,
+ /// SEL op, ...)
+ ///
+ /// The messenger used for super calls which return an aggregate indirectly.
llvm::Constant *getMessageSendSuperStretFn() const {
- // void objc_msgSendSuper_stret(void * stretAddr, struct objc_super *super,
- // SEL op, ...)
- std::vector<const llvm::Type*> Params;
- Params.push_back(Int8PtrTy);
- Params.push_back(SuperPtrTy);
- Params.push_back(SelectorPtrTy);
+ const llvm::Type *params[] = { Int8PtrTy, SuperPtrTy, SelectorPtrTy };
return CGM.CreateRuntimeFunction(
- llvm::FunctionType::get(llvm::Type::getVoidTy(VMContext),
- Params, true),
+ llvm::FunctionType::get(CGM.VoidTy, params, true),
"objc_msgSendSuper_stret");
}
+ /// void objc_msgSendSuper2_stret(void * stretAddr, struct objc_super *super,
+ /// SEL op, ...)
+ ///
+ /// objc_msgSendSuper_stret with the super2 semantics.
llvm::Constant *getMessageSendSuperStretFn2() const {
- // void objc_msgSendSuper2_stret(void * stretAddr, struct objc_super *super,
- // SEL op, ...)
- std::vector<const llvm::Type*> Params;
- Params.push_back(Int8PtrTy);
- Params.push_back(SuperPtrTy);
- Params.push_back(SelectorPtrTy);
+ const llvm::Type *params[] = { Int8PtrTy, SuperPtrTy, SelectorPtrTy };
return CGM.CreateRuntimeFunction(
- llvm::FunctionType::get(llvm::Type::getVoidTy(VMContext),
- Params, true),
+ llvm::FunctionType::get(CGM.VoidTy, params, true),
"objc_msgSendSuper2_stret");
}
@@ -282,107 +270,97 @@ public:
/// GcReadWeakFn -- LLVM objc_read_weak (id *src) function.
llvm::Constant *getGcReadWeakFn() {
// id objc_read_weak (id *)
- std::vector<const llvm::Type*> Args;
- Args.push_back(ObjectPtrTy->getPointerTo());
+ const llvm::Type *args[] = { ObjectPtrTy->getPointerTo() };
llvm::FunctionType *FTy =
- llvm::FunctionType::get(ObjectPtrTy, Args, false);
+ llvm::FunctionType::get(ObjectPtrTy, args, false);
return CGM.CreateRuntimeFunction(FTy, "objc_read_weak");
}
/// GcAssignWeakFn -- LLVM objc_assign_weak function.
llvm::Constant *getGcAssignWeakFn() {
// id objc_assign_weak (id, id *)
- std::vector<const llvm::Type*> Args(1, ObjectPtrTy);
- Args.push_back(ObjectPtrTy->getPointerTo());
+ const llvm::Type *args[] = { ObjectPtrTy, ObjectPtrTy->getPointerTo() };
llvm::FunctionType *FTy =
- llvm::FunctionType::get(ObjectPtrTy, Args, false);
+ llvm::FunctionType::get(ObjectPtrTy, args, false);
return CGM.CreateRuntimeFunction(FTy, "objc_assign_weak");
}
/// GcAssignGlobalFn -- LLVM objc_assign_global function.
llvm::Constant *getGcAssignGlobalFn() {
// id objc_assign_global(id, id *)
- std::vector<const llvm::Type*> Args(1, ObjectPtrTy);
- Args.push_back(ObjectPtrTy->getPointerTo());
+ const llvm::Type *args[] = { ObjectPtrTy, ObjectPtrTy->getPointerTo() };
llvm::FunctionType *FTy =
- llvm::FunctionType::get(ObjectPtrTy, Args, false);
+ llvm::FunctionType::get(ObjectPtrTy, args, false);
return CGM.CreateRuntimeFunction(FTy, "objc_assign_global");
}
/// GcAssignThreadLocalFn -- LLVM objc_assign_threadlocal function.
llvm::Constant *getGcAssignThreadLocalFn() {
// id objc_assign_threadlocal(id src, id * dest)
- std::vector<const llvm::Type*> Args(1, ObjectPtrTy);
- Args.push_back(ObjectPtrTy->getPointerTo());
+ const llvm::Type *args[] = { ObjectPtrTy, ObjectPtrTy->getPointerTo() };
llvm::FunctionType *FTy =
- llvm::FunctionType::get(ObjectPtrTy, Args, false);
+ llvm::FunctionType::get(ObjectPtrTy, args, false);
return CGM.CreateRuntimeFunction(FTy, "objc_assign_threadlocal");
}
/// GcAssignIvarFn -- LLVM objc_assign_ivar function.
llvm::Constant *getGcAssignIvarFn() {
// id objc_assign_ivar(id, id *, ptrdiff_t)
- std::vector<const llvm::Type*> Args(1, ObjectPtrTy);
- Args.push_back(ObjectPtrTy->getPointerTo());
- Args.push_back(LongTy);
+ const llvm::Type *args[] = { ObjectPtrTy, ObjectPtrTy->getPointerTo(),
+ CGM.PtrDiffTy };
llvm::FunctionType *FTy =
- llvm::FunctionType::get(ObjectPtrTy, Args, false);
+ llvm::FunctionType::get(ObjectPtrTy, args, false);
return CGM.CreateRuntimeFunction(FTy, "objc_assign_ivar");
}
/// GcMemmoveCollectableFn -- LLVM objc_memmove_collectable function.
llvm::Constant *GcMemmoveCollectableFn() {
// void *objc_memmove_collectable(void *dst, const void *src, size_t size)
- std::vector<const llvm::Type*> Args(1, Int8PtrTy);
- Args.push_back(Int8PtrTy);
- Args.push_back(LongTy);
- llvm::FunctionType *FTy = llvm::FunctionType::get(Int8PtrTy, Args, false);
+ const llvm::Type *args[] = { Int8PtrTy, Int8PtrTy, LongTy };
+ llvm::FunctionType *FTy = llvm::FunctionType::get(Int8PtrTy, args, false);
return CGM.CreateRuntimeFunction(FTy, "objc_memmove_collectable");
}
/// GcAssignStrongCastFn -- LLVM objc_assign_strongCast function.
llvm::Constant *getGcAssignStrongCastFn() {
// id objc_assign_strongCast(id, id *)
- std::vector<const llvm::Type*> Args(1, ObjectPtrTy);
- Args.push_back(ObjectPtrTy->getPointerTo());
+ const llvm::Type *args[] = { ObjectPtrTy, ObjectPtrTy->getPointerTo() };
llvm::FunctionType *FTy =
- llvm::FunctionType::get(ObjectPtrTy, Args, false);
+ llvm::FunctionType::get(ObjectPtrTy, args, false);
return CGM.CreateRuntimeFunction(FTy, "objc_assign_strongCast");
}
/// ExceptionThrowFn - LLVM objc_exception_throw function.
llvm::Constant *getExceptionThrowFn() {
// void objc_exception_throw(id)
- std::vector<const llvm::Type*> Args(1, ObjectPtrTy);
+ const llvm::Type *args[] = { ObjectPtrTy };
llvm::FunctionType *FTy =
- llvm::FunctionType::get(llvm::Type::getVoidTy(VMContext), Args, false);
+ llvm::FunctionType::get(CGM.VoidTy, args, false);
return CGM.CreateRuntimeFunction(FTy, "objc_exception_throw");
}
/// ExceptionRethrowFn - LLVM objc_exception_rethrow function.
llvm::Constant *getExceptionRethrowFn() {
// void objc_exception_rethrow(void)
- std::vector<const llvm::Type*> Args;
- llvm::FunctionType *FTy =
- llvm::FunctionType::get(llvm::Type::getVoidTy(VMContext), Args, false);
+ llvm::FunctionType *FTy = llvm::FunctionType::get(CGM.VoidTy, false);
return CGM.CreateRuntimeFunction(FTy, "objc_exception_rethrow");
}
/// SyncEnterFn - LLVM object_sync_enter function.
llvm::Constant *getSyncEnterFn() {
// void objc_sync_enter (id)
- std::vector<const llvm::Type*> Args(1, ObjectPtrTy);
+ const llvm::Type *args[] = { ObjectPtrTy };
llvm::FunctionType *FTy =
- llvm::FunctionType::get(llvm::Type::getVoidTy(VMContext), Args, false);
+ llvm::FunctionType::get(CGM.VoidTy, args, false);
return CGM.CreateRuntimeFunction(FTy, "objc_sync_enter");
}
/// SyncExitFn - LLVM object_sync_exit function.
llvm::Constant *getSyncExitFn() {
// void objc_sync_exit (id)
- std::vector<const llvm::Type*> Args(1, ObjectPtrTy);
+ const llvm::Type *args[] = { ObjectPtrTy };
llvm::FunctionType *FTy =
- llvm::FunctionType::get(llvm::Type::getVoidTy(VMContext), Args, false);
+ llvm::FunctionType::get(CGM.VoidTy, args, false);
return CGM.CreateRuntimeFunction(FTy, "objc_sync_exit");
}
@@ -474,55 +452,44 @@ public:
/// ExceptionTryEnterFn - LLVM objc_exception_try_enter function.
llvm::Constant *getExceptionTryEnterFn() {
- std::vector<const llvm::Type*> Params;
- Params.push_back(llvm::PointerType::getUnqual(ExceptionDataTy));
+ const llvm::Type *params[] = { ExceptionDataTy->getPointerTo() };
return CGM.CreateRuntimeFunction(
- llvm::FunctionType::get(llvm::Type::getVoidTy(VMContext),
- Params, false),
+ llvm::FunctionType::get(CGM.VoidTy, params, false),
"objc_exception_try_enter");
}
/// ExceptionTryExitFn - LLVM objc_exception_try_exit function.
llvm::Constant *getExceptionTryExitFn() {
- std::vector<const llvm::Type*> Params;
- Params.push_back(llvm::PointerType::getUnqual(ExceptionDataTy));
+ const llvm::Type *params[] = { ExceptionDataTy->getPointerTo() };
return CGM.CreateRuntimeFunction(
- llvm::FunctionType::get(llvm::Type::getVoidTy(VMContext),
- Params, false),
+ llvm::FunctionType::get(CGM.VoidTy, params, false),
"objc_exception_try_exit");
}
/// ExceptionExtractFn - LLVM objc_exception_extract function.
llvm::Constant *getExceptionExtractFn() {
- std::vector<const llvm::Type*> Params;
- Params.push_back(llvm::PointerType::getUnqual(ExceptionDataTy));
+ const llvm::Type *params[] = { ExceptionDataTy->getPointerTo() };
return CGM.CreateRuntimeFunction(llvm::FunctionType::get(ObjectPtrTy,
- Params, false),
+ params, false),
"objc_exception_extract");
-
}
/// ExceptionMatchFn - LLVM objc_exception_match function.
llvm::Constant *getExceptionMatchFn() {
- std::vector<const llvm::Type*> Params;
- Params.push_back(ClassPtrTy);
- Params.push_back(ObjectPtrTy);
+ const llvm::Type *params[] = { ClassPtrTy, ObjectPtrTy };
return CGM.CreateRuntimeFunction(
- llvm::FunctionType::get(llvm::Type::getInt32Ty(VMContext),
- Params, false),
+ llvm::FunctionType::get(CGM.Int32Ty, params, false),
"objc_exception_match");
}
/// SetJmpFn - LLVM _setjmp function.
llvm::Constant *getSetJmpFn() {
- std::vector<const llvm::Type*> Params;
- Params.push_back(llvm::Type::getInt32PtrTy(VMContext));
- return
- CGM.CreateRuntimeFunction(llvm::FunctionType::get(llvm::Type::getInt32Ty(VMContext),
- Params, false),
- "_setjmp");
-
+ // This is specifically the prototype for x86.
+ const llvm::Type *params[] = { CGM.Int32Ty->getPointerTo() };
+ return CGM.CreateRuntimeFunction(llvm::FunctionType::get(CGM.Int32Ty,
+ params, false),
+ "_setjmp");
}
public:
@@ -608,68 +575,56 @@ public:
llvm::Constant *getMessageSendFixupFn() {
// id objc_msgSend_fixup(id, struct message_ref_t*, ...)
- std::vector<const llvm::Type*> Params;
- Params.push_back(ObjectPtrTy);
- Params.push_back(MessageRefPtrTy);
+ const llvm::Type *params[] = { ObjectPtrTy, MessageRefPtrTy };
return CGM.CreateRuntimeFunction(llvm::FunctionType::get(ObjectPtrTy,
- Params, true),
+ params, true),
"objc_msgSend_fixup");
}
llvm::Constant *getMessageSendFpretFixupFn() {
// id objc_msgSend_fpret_fixup(id, struct message_ref_t*, ...)
- std::vector<const llvm::Type*> Params;
- Params.push_back(ObjectPtrTy);
- Params.push_back(MessageRefPtrTy);
+ const llvm::Type *params[] = { ObjectPtrTy, MessageRefPtrTy };
return CGM.CreateRuntimeFunction(llvm::FunctionType::get(ObjectPtrTy,
- Params, true),
+ params, true),
"objc_msgSend_fpret_fixup");
}
llvm::Constant *getMessageSendStretFixupFn() {
// id objc_msgSend_stret_fixup(id, struct message_ref_t*, ...)
- std::vector<const llvm::Type*> Params;
- Params.push_back(ObjectPtrTy);
- Params.push_back(MessageRefPtrTy);
+ const llvm::Type *params[] = { ObjectPtrTy, MessageRefPtrTy };
return CGM.CreateRuntimeFunction(llvm::FunctionType::get(ObjectPtrTy,
- Params, true),
+ params, true),
"objc_msgSend_stret_fixup");
}
llvm::Constant *getMessageSendSuper2FixupFn() {
// id objc_msgSendSuper2_fixup (struct objc_super *,
// struct _super_message_ref_t*, ...)
- std::vector<const llvm::Type*> Params;
- Params.push_back(SuperPtrTy);
- Params.push_back(SuperMessageRefPtrTy);
+ const llvm::Type *params[] = { SuperPtrTy, SuperMessageRefPtrTy };
return CGM.CreateRuntimeFunction(llvm::FunctionType::get(ObjectPtrTy,
- Params, true),
+ params, true),
"objc_msgSendSuper2_fixup");
}
llvm::Constant *getMessageSendSuper2StretFixupFn() {
// id objc_msgSendSuper2_stret_fixup(struct objc_super *,
// struct _super_message_ref_t*, ...)
- std::vector<const llvm::Type*> Params;
- Params.push_back(SuperPtrTy);
- Params.push_back(SuperMessageRefPtrTy);
+ const llvm::Type *params[] = { SuperPtrTy, SuperMessageRefPtrTy };
return CGM.CreateRuntimeFunction(llvm::FunctionType::get(ObjectPtrTy,
- Params, true),
+ params, true),
"objc_msgSendSuper2_stret_fixup");
}
llvm::Constant *getObjCEndCatchFn() {
- return CGM.CreateRuntimeFunction(llvm::FunctionType::get(llvm::Type::getVoidTy(VMContext),
- false),
+ return CGM.CreateRuntimeFunction(llvm::FunctionType::get(CGM.VoidTy, false),
"objc_end_catch");
}
llvm::Constant *getObjCBeginCatchFn() {
- std::vector<const llvm::Type*> Params;
- Params.push_back(Int8PtrTy);
+ const llvm::Type *params[] = { Int8PtrTy };
return CGM.CreateRuntimeFunction(llvm::FunctionType::get(Int8PtrTy,
- Params, false),
+ params, false),
"objc_begin_catch");
}
@@ -865,16 +820,16 @@ protected:
unsigned Align,
bool AddToUsed);
- CodeGen::RValue EmitLegacyMessageSend(CodeGen::CodeGenFunction &CGF,
- ReturnValueSlot Return,
- QualType ResultType,
- llvm::Value *Sel,
- llvm::Value *Arg0,
- QualType Arg0Ty,
- bool IsSuper,
- const CallArgList &CallArgs,
- const ObjCMethodDecl *OMD,
- const ObjCCommonTypesHelper &ObjCTypes);
+ CodeGen::RValue EmitMessageSend(CodeGen::CodeGenFunction &CGF,
+ ReturnValueSlot Return,
+ QualType ResultType,
+ llvm::Value *Sel,
+ llvm::Value *Arg0,
+ QualType Arg0Ty,
+ bool IsSuper,
+ const CallArgList &CallArgs,
+ const ObjCMethodDecl *OMD,
+ const ObjCCommonTypesHelper &ObjCTypes);
/// EmitImageInfo - Emit the image info marker used to encode some module
/// level information.
@@ -1093,6 +1048,13 @@ public:
virtual llvm::Value *EmitIvarOffset(CodeGen::CodeGenFunction &CGF,
const ObjCInterfaceDecl *Interface,
const ObjCIvarDecl *Ivar);
+
+ /// GetClassGlobal - Return the global variable for the Objective-C
+ /// class of the given name.
+ virtual llvm::GlobalVariable *GetClassGlobal(const std::string &Name) {
+ assert(false && "CGObjCMac::GetClassGlobal");
+ return 0;
+ }
};
class CGObjCNonFragileABIMac : public CGObjCCommonMac {
@@ -1110,16 +1072,16 @@ private:
/// EHTypeReferences - uniqued class ehtype references.
llvm::DenseMap<IdentifierInfo*, llvm::GlobalVariable*> EHTypeReferences;
- /// NonLegacyDispatchMethods - List of methods for which we do *not* generate
- /// legacy messaging dispatch.
- llvm::DenseSet<Selector> NonLegacyDispatchMethods;
+ /// VTableDispatchMethods - List of methods for which we generate
+ /// vtable-based message dispatch.
+ llvm::DenseSet<Selector> VTableDispatchMethods;
/// DefinedMetaClasses - List of defined meta-classes.
std::vector<llvm::GlobalValue*> DefinedMetaClasses;
- /// LegacyDispatchedSelector - Returns true if SEL is not in the list of
- /// NonLegacyDispatchMethods; false otherwise.
- bool LegacyDispatchedSelector(Selector Sel);
+ /// isVTableDispatchedSelector - Returns true if SEL is a
+ /// vtable-based selector.
+ bool isVTableDispatchedSelector(Selector Sel);
/// FinishNonFragileABIModule - Write out global data structures at the end of
/// processing a translation unit.
@@ -1178,20 +1140,20 @@ private:
ObjCProtocolDecl::protocol_iterator begin,
ObjCProtocolDecl::protocol_iterator end);
- CodeGen::RValue EmitMessageSend(CodeGen::CodeGenFunction &CGF,
- ReturnValueSlot Return,
- QualType ResultType,
- Selector Sel,
- llvm::Value *Receiver,
- QualType Arg0Ty,
- bool IsSuper,
- const CallArgList &CallArgs,
- const ObjCMethodDecl *Method);
-
+ CodeGen::RValue EmitVTableMessageSend(CodeGen::CodeGenFunction &CGF,
+ ReturnValueSlot Return,
+ QualType ResultType,
+ Selector Sel,
+ llvm::Value *Receiver,
+ QualType Arg0Ty,
+ bool IsSuper,
+ const CallArgList &CallArgs,
+ const ObjCMethodDecl *Method);
+
/// GetClassGlobal - Return the global variable for the Objective-C
/// class of the given name.
llvm::GlobalVariable *GetClassGlobal(const std::string &Name);
-
+
/// EmitClassRef - Return a Value*, of type ObjCTypes.ClassPtrTy,
/// for the given class reference.
llvm::Value *EmitClassRef(CGBuilderTy &Builder,
@@ -1347,6 +1309,46 @@ public:
const ObjCIvarDecl *Ivar);
};
+/// A helper class for performing the null-initialization of a return
+/// value.
+struct NullReturnState {
+ llvm::BasicBlock *NullBB;
+
+ NullReturnState() : NullBB(0) {}
+
+ void init(CodeGenFunction &CGF, llvm::Value *receiver) {
+ // Make blocks for the null-init and call edges.
+ NullBB = CGF.createBasicBlock("msgSend.nullinit");
+ llvm::BasicBlock *callBB = CGF.createBasicBlock("msgSend.call");
+
+ // Check for a null receiver and, if there is one, jump to the
+ // null-init test.
+ llvm::Value *isNull = CGF.Builder.CreateIsNull(receiver);
+ CGF.Builder.CreateCondBr(isNull, NullBB, callBB);
+
+ // Otherwise, start performing the call.
+ CGF.EmitBlock(callBB);
+ }
+
+ RValue complete(CodeGenFunction &CGF, RValue result, QualType resultType) {
+ if (!NullBB) return result;
+
+ // Finish the call path.
+ llvm::BasicBlock *contBB = CGF.createBasicBlock("msgSend.cont");
+ if (CGF.HaveInsertPoint()) CGF.Builder.CreateBr(contBB);
+
+ // Emit the null-init block and perform the null-initialization there.
+ CGF.EmitBlock(NullBB);
+ assert(result.isAggregate() && "null init of non-aggregate result?");
+ CGF.EmitNullInitialization(result.getAggregateAddr(), resultType);
+
+ // Jump to the continuation block.
+ CGF.EmitBlock(contBB);
+
+ return result;
+ }
+};
+
} // end anonymous namespace
/* *** Helper Functions *** */
@@ -1487,10 +1489,10 @@ CGObjCMac::GenerateMessageSendSuper(CodeGen::CodeGenFunction &CGF,
Target = CGF.Builder.CreateBitCast(Target, ClassTy);
CGF.Builder.CreateStore(Target,
CGF.Builder.CreateStructGEP(ObjCSuper, 1));
- return EmitLegacyMessageSend(CGF, Return, ResultType,
- EmitSelector(CGF.Builder, Sel),
- ObjCSuper, ObjCTypes.SuperPtrCTy,
- true, CallArgs, Method, ObjCTypes);
+ return EmitMessageSend(CGF, Return, ResultType,
+ EmitSelector(CGF.Builder, Sel),
+ ObjCSuper, ObjCTypes.SuperPtrCTy,
+ true, CallArgs, Method, ObjCTypes);
}
/// Generate code for a message send expression.
@@ -1502,23 +1504,23 @@ CodeGen::RValue CGObjCMac::GenerateMessageSend(CodeGen::CodeGenFunction &CGF,
const CallArgList &CallArgs,
const ObjCInterfaceDecl *Class,
const ObjCMethodDecl *Method) {
- return EmitLegacyMessageSend(CGF, Return, ResultType,
- EmitSelector(CGF.Builder, Sel),
- Receiver, CGF.getContext().getObjCIdType(),
- false, CallArgs, Method, ObjCTypes);
+ return EmitMessageSend(CGF, Return, ResultType,
+ EmitSelector(CGF.Builder, Sel),
+ Receiver, CGF.getContext().getObjCIdType(),
+ false, CallArgs, Method, ObjCTypes);
}
CodeGen::RValue
-CGObjCCommonMac::EmitLegacyMessageSend(CodeGen::CodeGenFunction &CGF,
- ReturnValueSlot Return,
- QualType ResultType,
- llvm::Value *Sel,
- llvm::Value *Arg0,
- QualType Arg0Ty,
- bool IsSuper,
- const CallArgList &CallArgs,
- const ObjCMethodDecl *Method,
- const ObjCCommonTypesHelper &ObjCTypes) {
+CGObjCCommonMac::EmitMessageSend(CodeGen::CodeGenFunction &CGF,
+ ReturnValueSlot Return,
+ QualType ResultType,
+ llvm::Value *Sel,
+ llvm::Value *Arg0,
+ QualType Arg0Ty,
+ bool IsSuper,
+ const CallArgList &CallArgs,
+ const ObjCMethodDecl *Method,
+ const ObjCCommonTypesHelper &ObjCTypes) {
CallArgList ActualArgs;
if (!IsSuper)
Arg0 = CGF.Builder.CreateBitCast(Arg0, ObjCTypes.ObjectPtrTy, "tmp");
@@ -1537,9 +1539,11 @@ CGObjCCommonMac::EmitLegacyMessageSend(CodeGen::CodeGenFunction &CGF,
CGM.getContext().getCanonicalType(ResultType) &&
"Result type mismatch!");
+ NullReturnState nullReturn;
+
llvm::Constant *Fn = NULL;
if (CGM.ReturnTypeUsesSRet(FnInfo)) {
- EmitNullReturnInitialization(CGF, Return, ResultType);
+ if (!IsSuper) nullReturn.init(CGF, Arg0);
Fn = (ObjCABI == 2) ? ObjCTypes.getSendStretFn2(IsSuper)
: ObjCTypes.getSendStretFn(IsSuper);
} else if (CGM.ReturnTypeUsesFPRet(ResultType)) {
@@ -1550,7 +1554,8 @@ CGObjCCommonMac::EmitLegacyMessageSend(CodeGen::CodeGenFunction &CGF,
: ObjCTypes.getSendFn(IsSuper);
}
Fn = llvm::ConstantExpr::getBitCast(Fn, llvm::PointerType::getUnqual(FTy));
- return CGF.EmitCall(FnInfo, Fn, Return, ActualArgs);
+ RValue rvalue = CGF.EmitCall(FnInfo, Fn, Return, ActualArgs);
+ return nullReturn.complete(CGF, rvalue, ResultType);
}
static Qualifiers::GC GetGCAttrTypeForType(ASTContext &Ctx, QualType FQT) {
@@ -1681,6 +1686,7 @@ void CGObjCCommonMac::GenerateProtocol(const ObjCProtocolDecl *PD) {
llvm::Constant *CGObjCCommonMac::GetProtocolRef(const ObjCProtocolDecl *PD) {
if (DefinedProtocols.count(PD->getIdentifier()))
return GetOrEmitProtocol(PD);
+
return GetOrEmitProtocolRef(PD);
}
@@ -1714,6 +1720,9 @@ llvm::Constant *CGObjCMac::GetOrEmitProtocol(const ObjCProtocolDecl *PD) {
i = PD->instmeth_begin(), e = PD->instmeth_end(); i != e; ++i) {
ObjCMethodDecl *MD = *i;
llvm::Constant *C = GetMethodDescriptionConstant(MD);
+ if (!C)
+ return GetOrEmitProtocolRef(PD);
+
if (MD->getImplementationControl() == ObjCMethodDecl::Optional) {
OptInstanceMethods.push_back(C);
} else {
@@ -1725,6 +1734,9 @@ llvm::Constant *CGObjCMac::GetOrEmitProtocol(const ObjCProtocolDecl *PD) {
i = PD->classmeth_begin(), e = PD->classmeth_end(); i != e; ++i) {
ObjCMethodDecl *MD = *i;
llvm::Constant *C = GetMethodDescriptionConstant(MD);
+ if (!C)
+ return GetOrEmitProtocolRef(PD);
+
if (MD->getImplementationControl() == ObjCMethodDecl::Optional) {
OptClassMethods.push_back(C);
} else {
@@ -1968,6 +1980,9 @@ CGObjCMac::GetMethodDescriptionConstant(const ObjCMethodDecl *MD) {
llvm::ConstantExpr::getBitCast(GetMethodVarName(MD->getSelector()),
ObjCTypes.SelectorPtrTy);
Desc[1] = GetMethodVarType(MD);
+ if (!Desc[1])
+ return 0;
+
return llvm::ConstantStruct::get(ObjCTypes.MethodDescriptionTy,
Desc);
}
@@ -2730,10 +2745,10 @@ void FragileHazards::collectLocals() {
}
llvm::FunctionType *FragileHazards::GetAsmFnType() {
- std::vector<const llvm::Type *> Tys(Locals.size());
- for (unsigned I = 0, E = Locals.size(); I != E; ++I)
- Tys[I] = Locals[I]->getType();
- return llvm::FunctionType::get(CGF.Builder.getVoidTy(), Tys, false);
+ llvm::SmallVector<const llvm::Type *, 16> tys(Locals.size());
+ for (unsigned i = 0, e = Locals.size(); i != e; ++i)
+ tys[i] = Locals[i]->getType();
+ return llvm::FunctionType::get(CGF.VoidTy, tys, false);
}
/*
@@ -3930,8 +3945,10 @@ llvm::Constant *CGObjCCommonMac::GetMethodVarType(const FieldDecl *Field) {
llvm::Constant *CGObjCCommonMac::GetMethodVarType(const ObjCMethodDecl *D) {
std::string TypeStr;
- CGM.getContext().getObjCEncodingForMethodDecl(const_cast<ObjCMethodDecl*>(D),
- TypeStr);
+ if (CGM.getContext().getObjCEncodingForMethodDecl(
+ const_cast<ObjCMethodDecl*>(D),
+ TypeStr))
+ return 0;
llvm::GlobalVariable *&Entry = MethodVarTypes[TypeStr];
@@ -4081,9 +4098,9 @@ ObjCCommonTypesHelper::ObjCCommonTypesHelper(CodeGen::CodeGenModule &cgm)
SourceLocation(), SourceLocation(),
&Ctx.Idents.get("_objc_super"));
RD->addDecl(FieldDecl::Create(Ctx, RD, SourceLocation(), SourceLocation(), 0,
- Ctx.getObjCIdType(), 0, 0, false));
+ Ctx.getObjCIdType(), 0, 0, false, false));
RD->addDecl(FieldDecl::Create(Ctx, RD, SourceLocation(), SourceLocation(), 0,
- Ctx.getObjCClassType(), 0, 0, false));
+ Ctx.getObjCClassType(), 0, 0, false, false));
RD->completeDefinition();
SuperCTy = Ctx.getTagDeclType(RD);
@@ -4480,11 +4497,9 @@ ObjCNonFragileABITypesHelper::ObjCNonFragileABITypesHelper(CodeGen::CodeGenModul
ClassRonfABITy);
// ImpnfABITy - LLVM for id (*)(id, SEL, ...)
- std::vector<const llvm::Type*> Params;
- Params.push_back(ObjectPtrTy);
- Params.push_back(SelectorPtrTy);
- ImpnfABITy = llvm::PointerType::getUnqual(
- llvm::FunctionType::get(ObjectPtrTy, Params, false));
+ const llvm::Type *params[] = { ObjectPtrTy, SelectorPtrTy };
+ ImpnfABITy = llvm::FunctionType::get(ObjectPtrTy, params, false)
+ ->getPointerTo();
// struct _class_t {
// struct _class_t *isa;
@@ -4544,9 +4559,9 @@ ObjCNonFragileABITypesHelper::ObjCNonFragileABITypesHelper(CodeGen::CodeGenModul
SourceLocation(), SourceLocation(),
&Ctx.Idents.get("_message_ref_t"));
RD->addDecl(FieldDecl::Create(Ctx, RD, SourceLocation(), SourceLocation(), 0,
- Ctx.VoidPtrTy, 0, 0, false));
+ Ctx.VoidPtrTy, 0, 0, false, false));
RD->addDecl(FieldDecl::Create(Ctx, RD, SourceLocation(), SourceLocation(), 0,
- Ctx.getObjCSelType(), 0, 0, false));
+ Ctx.getObjCSelType(), 0, 0, false, false));
RD->completeDefinition();
MessageRefCTy = Ctx.getTagDeclType(RD);
@@ -4658,56 +4673,68 @@ void CGObjCNonFragileABIMac::FinishNonFragileABIModule() {
EmitImageInfo();
}
-/// LegacyDispatchedSelector - Returns true if SEL is not in the list of
-/// NonLegacyDispatchMethods; false otherwise. What this means is that
+/// isVTableDispatchedSelector - Returns true if SEL is not in the list of
+/// VTableDispatchMethods; false otherwise. What this means is that
/// except for the 19 selectors in the list, we generate 32bit-style
/// message dispatch call for all the rest.
-///
-bool CGObjCNonFragileABIMac::LegacyDispatchedSelector(Selector Sel) {
+bool CGObjCNonFragileABIMac::isVTableDispatchedSelector(Selector Sel) {
+ // At various points we've experimented with using vtable-based
+ // dispatch for all methods.
switch (CGM.getCodeGenOpts().getObjCDispatchMethod()) {
default:
- assert(0 && "Invalid dispatch method!");
+ llvm_unreachable("Invalid dispatch method!");
case CodeGenOptions::Legacy:
- return true;
- case CodeGenOptions::NonLegacy:
return false;
+ case CodeGenOptions::NonLegacy:
+ return true;
case CodeGenOptions::Mixed:
break;
}
// If so, see whether this selector is in the white-list of things which must
// use the new dispatch convention. We lazily build a dense set for this.
- if (NonLegacyDispatchMethods.empty()) {
- NonLegacyDispatchMethods.insert(GetNullarySelector("alloc"));
- NonLegacyDispatchMethods.insert(GetNullarySelector("class"));
- NonLegacyDispatchMethods.insert(GetNullarySelector("self"));
- NonLegacyDispatchMethods.insert(GetNullarySelector("isFlipped"));
- NonLegacyDispatchMethods.insert(GetNullarySelector("length"));
- NonLegacyDispatchMethods.insert(GetNullarySelector("count"));
- NonLegacyDispatchMethods.insert(GetNullarySelector("retain"));
- NonLegacyDispatchMethods.insert(GetNullarySelector("release"));
- NonLegacyDispatchMethods.insert(GetNullarySelector("autorelease"));
- NonLegacyDispatchMethods.insert(GetNullarySelector("hash"));
-
- NonLegacyDispatchMethods.insert(GetUnarySelector("allocWithZone"));
- NonLegacyDispatchMethods.insert(GetUnarySelector("isKindOfClass"));
- NonLegacyDispatchMethods.insert(GetUnarySelector("respondsToSelector"));
- NonLegacyDispatchMethods.insert(GetUnarySelector("objectForKey"));
- NonLegacyDispatchMethods.insert(GetUnarySelector("objectAtIndex"));
- NonLegacyDispatchMethods.insert(GetUnarySelector("isEqualToString"));
- NonLegacyDispatchMethods.insert(GetUnarySelector("isEqual"));
- NonLegacyDispatchMethods.insert(GetUnarySelector("addObject"));
- // "countByEnumeratingWithState:objects:count"
- IdentifierInfo *KeyIdents[] = {
- &CGM.getContext().Idents.get("countByEnumeratingWithState"),
- &CGM.getContext().Idents.get("objects"),
- &CGM.getContext().Idents.get("count")
- };
- NonLegacyDispatchMethods.insert(
- CGM.getContext().Selectors.getSelector(3, KeyIdents));
- }
-
- return (NonLegacyDispatchMethods.count(Sel) == 0);
+ if (VTableDispatchMethods.empty()) {
+ VTableDispatchMethods.insert(GetNullarySelector("alloc"));
+ VTableDispatchMethods.insert(GetNullarySelector("class"));
+ VTableDispatchMethods.insert(GetNullarySelector("self"));
+ VTableDispatchMethods.insert(GetNullarySelector("isFlipped"));
+ VTableDispatchMethods.insert(GetNullarySelector("length"));
+ VTableDispatchMethods.insert(GetNullarySelector("count"));
+
+ // These are vtable-based if GC is disabled.
+ // Optimistically use vtable dispatch for hybrid compiles.
+ if (CGM.getLangOptions().getGCMode() != LangOptions::GCOnly) {
+ VTableDispatchMethods.insert(GetNullarySelector("retain"));
+ VTableDispatchMethods.insert(GetNullarySelector("release"));
+ VTableDispatchMethods.insert(GetNullarySelector("autorelease"));
+ }
+
+ VTableDispatchMethods.insert(GetUnarySelector("allocWithZone"));
+ VTableDispatchMethods.insert(GetUnarySelector("isKindOfClass"));
+ VTableDispatchMethods.insert(GetUnarySelector("respondsToSelector"));
+ VTableDispatchMethods.insert(GetUnarySelector("objectForKey"));
+ VTableDispatchMethods.insert(GetUnarySelector("objectAtIndex"));
+ VTableDispatchMethods.insert(GetUnarySelector("isEqualToString"));
+ VTableDispatchMethods.insert(GetUnarySelector("isEqual"));
+
+ // These are vtable-based if GC is enabled.
+ // Optimistically use vtable dispatch for hybrid compiles.
+ if (CGM.getLangOptions().getGCMode() != LangOptions::NonGC) {
+ VTableDispatchMethods.insert(GetNullarySelector("hash"));
+ VTableDispatchMethods.insert(GetUnarySelector("addObject"));
+
+ // "countByEnumeratingWithState:objects:count"
+ IdentifierInfo *KeyIdents[] = {
+ &CGM.getContext().Idents.get("countByEnumeratingWithState"),
+ &CGM.getContext().Idents.get("objects"),
+ &CGM.getContext().Idents.get("count")
+ };
+ VTableDispatchMethods.insert(
+ CGM.getContext().Selectors.getSelector(3, KeyIdents));
+ }
+ }
+
+ return VTableDispatchMethods.count(Sel);
}
// Metadata flags
@@ -5209,7 +5236,7 @@ CGObjCNonFragileABIMac::EmitIvarOffsetVar(const ObjCInterfaceDecl *ID,
IvarOffsetGV->setVisibility(llvm::GlobalValue::HiddenVisibility);
else
IvarOffsetGV->setVisibility(llvm::GlobalValue::DefaultVisibility);
- IvarOffsetGV->setSection("__DATA, __objc_const");
+ IvarOffsetGV->setSection("__DATA, __objc_ivar");
return IvarOffsetGV;
}
@@ -5344,6 +5371,9 @@ llvm::Constant *CGObjCNonFragileABIMac::GetOrEmitProtocol(
i = PD->instmeth_begin(), e = PD->instmeth_end(); i != e; ++i) {
ObjCMethodDecl *MD = *i;
llvm::Constant *C = GetMethodDescriptionConstant(MD);
+ if (!C)
+ return GetOrEmitProtocolRef(PD);
+
if (MD->getImplementationControl() == ObjCMethodDecl::Optional) {
OptInstanceMethods.push_back(C);
} else {
@@ -5355,6 +5385,9 @@ llvm::Constant *CGObjCNonFragileABIMac::GetOrEmitProtocol(
i = PD->classmeth_begin(), e = PD->classmeth_end(); i != e; ++i) {
ObjCMethodDecl *MD = *i;
llvm::Constant *C = GetMethodDescriptionConstant(MD);
+ if (!C)
+ return GetOrEmitProtocolRef(PD);
+
if (MD->getImplementationControl() == ObjCMethodDecl::Optional) {
OptClassMethods.push_back(C);
} else {
@@ -5494,6 +5527,9 @@ CGObjCNonFragileABIMac::GetMethodDescriptionConstant(const ObjCMethodDecl *MD) {
llvm::ConstantExpr::getBitCast(GetMethodVarName(MD->getSelector()),
ObjCTypes.SelectorPtrTy);
Desc[1] = GetMethodVarType(MD);
+ if (!Desc[1])
+ return 0;
+
// Protocol methods have no implementation. So, this entry is always NULL.
Desc[2] = llvm::Constant::getNullValue(ObjCTypes.Int8PtrTy);
return llvm::ConstantStruct::get(ObjCTypes.MethodTy, Desc);
@@ -5523,90 +5559,131 @@ llvm::Value *CGObjCNonFragileABIMac::EmitIvarOffset(
return CGF.Builder.CreateLoad(ObjCIvarOffsetVariable(Interface, Ivar),"ivar");
}
-CodeGen::RValue CGObjCNonFragileABIMac::EmitMessageSend(
- CodeGen::CodeGenFunction &CGF,
- ReturnValueSlot Return,
- QualType ResultType,
- Selector Sel,
- llvm::Value *Receiver,
- QualType Arg0Ty,
- bool IsSuper,
- const CallArgList &CallArgs,
- const ObjCMethodDecl *Method) {
- // FIXME. Even though IsSuper is passes. This function doese not handle calls
- // to 'super' receivers.
- CodeGenTypes &Types = CGM.getTypes();
- llvm::Value *Arg0 = Receiver;
- if (!IsSuper)
- Arg0 = CGF.Builder.CreateBitCast(Arg0, ObjCTypes.ObjectPtrTy, "tmp");
+static void appendSelectorForMessageRefTable(std::string &buffer,
+ Selector selector) {
+ if (selector.isUnarySelector()) {
+ buffer += selector.getNameForSlot(0);
+ return;
+ }
- // Find the message function name.
- // FIXME. This is too much work to get the ABI-specific result type needed to
- // find the message name.
- const CGFunctionInfo &FnInfo
- = Types.getFunctionInfo(ResultType, CallArgList(),
- FunctionType::ExtInfo());
- llvm::Constant *Fn = 0;
- std::string Name("\01l_");
- if (CGM.ReturnTypeUsesSRet(FnInfo)) {
- EmitNullReturnInitialization(CGF, Return, ResultType);
- if (IsSuper) {
- Fn = ObjCTypes.getMessageSendSuper2StretFixupFn();
- Name += "objc_msgSendSuper2_stret_fixup";
+ for (unsigned i = 0, e = selector.getNumArgs(); i != e; ++i) {
+ buffer += selector.getNameForSlot(i);
+ buffer += '_';
+ }
+}
+
+/// Emit a "v-table" message send. We emit a weak hidden-visibility
+/// struct, initially containing the selector pointer and a pointer to
+/// a "fixup" variant of the appropriate objc_msgSend. To call, we
+/// load and call the function pointer, passing the address of the
+/// struct as the second parameter. The runtime determines whether
+/// the selector is currently emitted using vtable dispatch; if so, it
+/// substitutes a stub function which simply tail-calls through the
+/// appropriate vtable slot, and if not, it substitues a stub function
+/// which tail-calls objc_msgSend. Both stubs adjust the selector
+/// argument to correctly point to the selector.
+RValue
+CGObjCNonFragileABIMac::EmitVTableMessageSend(CodeGenFunction &CGF,
+ ReturnValueSlot returnSlot,
+ QualType resultType,
+ Selector selector,
+ llvm::Value *arg0,
+ QualType arg0Type,
+ bool isSuper,
+ const CallArgList &formalArgs,
+ const ObjCMethodDecl *method) {
+ // Compute the actual arguments.
+ CallArgList args;
+
+ // First argument: the receiver / super-call structure.
+ if (!isSuper)
+ arg0 = CGF.Builder.CreateBitCast(arg0, ObjCTypes.ObjectPtrTy);
+ args.add(RValue::get(arg0), arg0Type);
+
+ // Second argument: a pointer to the message ref structure. Leave
+ // the actual argument value blank for now.
+ args.add(RValue::get(0), ObjCTypes.MessageRefCPtrTy);
+
+ args.insert(args.end(), formalArgs.begin(), formalArgs.end());
+
+ const CGFunctionInfo &fnInfo =
+ CGM.getTypes().getFunctionInfo(resultType, args,
+ FunctionType::ExtInfo());
+
+ NullReturnState nullReturn;
+
+ // Find the function to call and the mangled name for the message
+ // ref structure. Using a different mangled name wouldn't actually
+ // be a problem; it would just be a waste.
+ //
+ // The runtime currently never uses vtable dispatch for anything
+ // except normal, non-super message-sends.
+ // FIXME: don't use this for that.
+ llvm::Constant *fn = 0;
+ std::string messageRefName("\01l_");
+ if (CGM.ReturnTypeUsesSRet(fnInfo)) {
+ if (isSuper) {
+ fn = ObjCTypes.getMessageSendSuper2StretFixupFn();
+ messageRefName += "objc_msgSendSuper2_stret_fixup";
} else {
- Fn = ObjCTypes.getMessageSendStretFixupFn();
- Name += "objc_msgSend_stret_fixup";
+ nullReturn.init(CGF, arg0);
+ fn = ObjCTypes.getMessageSendStretFixupFn();
+ messageRefName += "objc_msgSend_stret_fixup";
}
- } else if (!IsSuper && CGM.ReturnTypeUsesFPRet(ResultType)) {
- Fn = ObjCTypes.getMessageSendFpretFixupFn();
- Name += "objc_msgSend_fpret_fixup";
+ } else if (!isSuper && CGM.ReturnTypeUsesFPRet(resultType)) {
+ fn = ObjCTypes.getMessageSendFpretFixupFn();
+ messageRefName += "objc_msgSend_fpret_fixup";
} else {
- if (IsSuper) {
- Fn = ObjCTypes.getMessageSendSuper2FixupFn();
- Name += "objc_msgSendSuper2_fixup";
+ if (isSuper) {
+ fn = ObjCTypes.getMessageSendSuper2FixupFn();
+ messageRefName += "objc_msgSendSuper2_fixup";
} else {
- Fn = ObjCTypes.getMessageSendFixupFn();
- Name += "objc_msgSend_fixup";
+ fn = ObjCTypes.getMessageSendFixupFn();
+ messageRefName += "objc_msgSend_fixup";
}
}
- assert(Fn && "CGObjCNonFragileABIMac::EmitMessageSend");
- Name += '_';
- std::string SelName(Sel.getAsString());
- // Replace all ':' in selector name with '_' ouch!
- for (unsigned i = 0; i < SelName.size(); i++)
- if (SelName[i] == ':')
- SelName[i] = '_';
- Name += SelName;
- llvm::GlobalVariable *GV = CGM.getModule().getGlobalVariable(Name);
- if (!GV) {
- // Build message ref table entry.
- std::vector<llvm::Constant*> Values(2);
- Values[0] = Fn;
- Values[1] = GetMethodVarName(Sel);
- llvm::Constant *Init = llvm::ConstantStruct::get(VMContext, Values, false);
- GV = new llvm::GlobalVariable(CGM.getModule(), Init->getType(), false,
- llvm::GlobalValue::WeakAnyLinkage,
- Init,
- Name);
- GV->setVisibility(llvm::GlobalValue::HiddenVisibility);
- GV->setAlignment(16);
- GV->setSection("__DATA, __objc_msgrefs, coalesced");
- }
- llvm::Value *Arg1 = CGF.Builder.CreateBitCast(GV, ObjCTypes.MessageRefPtrTy);
-
- CallArgList ActualArgs;
- ActualArgs.add(RValue::get(Arg0), Arg0Ty);
- ActualArgs.add(RValue::get(Arg1), ObjCTypes.MessageRefCPtrTy);
- ActualArgs.insert(ActualArgs.end(), CallArgs.begin(), CallArgs.end());
- const CGFunctionInfo &FnInfo1 = Types.getFunctionInfo(ResultType, ActualArgs,
- FunctionType::ExtInfo());
- llvm::Value *Callee = CGF.Builder.CreateStructGEP(Arg1, 0);
- Callee = CGF.Builder.CreateLoad(Callee);
- const llvm::FunctionType *FTy =
- Types.GetFunctionType(FnInfo1, Method ? Method->isVariadic() : false);
- Callee = CGF.Builder.CreateBitCast(Callee,
- llvm::PointerType::getUnqual(FTy));
- return CGF.EmitCall(FnInfo1, Callee, Return, ActualArgs);
+ assert(fn && "CGObjCNonFragileABIMac::EmitMessageSend");
+ messageRefName += '_';
+
+ // Append the selector name, except use underscores anywhere we
+ // would have used colons.
+ appendSelectorForMessageRefTable(messageRefName, selector);
+
+ llvm::GlobalVariable *messageRef
+ = CGM.getModule().getGlobalVariable(messageRefName);
+ if (!messageRef) {
+ // Build the message ref structure.
+ llvm::Constant *values[] = { fn, GetMethodVarName(selector) };
+ llvm::Constant *init =
+ llvm::ConstantStruct::get(VMContext, values, 2, false);
+ messageRef = new llvm::GlobalVariable(CGM.getModule(),
+ init->getType(),
+ /*constant*/ false,
+ llvm::GlobalValue::WeakAnyLinkage,
+ init,
+ messageRefName);
+ messageRef->setVisibility(llvm::GlobalValue::HiddenVisibility);
+ messageRef->setAlignment(16);
+ messageRef->setSection("__DATA, __objc_msgrefs, coalesced");
+ }
+ llvm::Value *mref =
+ CGF.Builder.CreateBitCast(messageRef, ObjCTypes.MessageRefPtrTy);
+
+ // Update the message ref argument.
+ args[1].RV = RValue::get(mref);
+
+ // Load the function to call from the message ref table.
+ llvm::Value *callee = CGF.Builder.CreateStructGEP(mref, 0);
+ callee = CGF.Builder.CreateLoad(callee, "msgSend_fn");
+
+ bool variadic = method ? method->isVariadic() : false;
+ const llvm::FunctionType *fnType =
+ CGF.getTypes().GetFunctionType(fnInfo, variadic);
+ callee = CGF.Builder.CreateBitCast(callee,
+ llvm::PointerType::getUnqual(fnType));
+
+ RValue result = CGF.EmitCall(fnInfo, callee, returnSlot, args);
+ return nullReturn.complete(CGF, result, resultType);
}
/// Generate code for a message send expression in the nonfragile abi.
@@ -5619,14 +5696,14 @@ CGObjCNonFragileABIMac::GenerateMessageSend(CodeGen::CodeGenFunction &CGF,
const CallArgList &CallArgs,
const ObjCInterfaceDecl *Class,
const ObjCMethodDecl *Method) {
- return LegacyDispatchedSelector(Sel)
- ? EmitLegacyMessageSend(CGF, Return, ResultType,
- EmitSelector(CGF.Builder, Sel),
+ return isVTableDispatchedSelector(Sel)
+ ? EmitVTableMessageSend(CGF, Return, ResultType, Sel,
Receiver, CGF.getContext().getObjCIdType(),
- false, CallArgs, Method, ObjCTypes)
- : EmitMessageSend(CGF, Return, ResultType, Sel,
+ false, CallArgs, Method)
+ : EmitMessageSend(CGF, Return, ResultType,
+ EmitSelector(CGF.Builder, Sel),
Receiver, CGF.getContext().getObjCIdType(),
- false, CallArgs, Method);
+ false, CallArgs, Method, ObjCTypes);
}
llvm::GlobalVariable *
@@ -5773,14 +5850,14 @@ CGObjCNonFragileABIMac::GenerateMessageSendSuper(CodeGen::CodeGenFunction &CGF,
CGF.Builder.CreateStore(Target,
CGF.Builder.CreateStructGEP(ObjCSuper, 1));
- return (LegacyDispatchedSelector(Sel))
- ? EmitLegacyMessageSend(CGF, Return, ResultType,
- EmitSelector(CGF.Builder, Sel),
+ return (isVTableDispatchedSelector(Sel))
+ ? EmitVTableMessageSend(CGF, Return, ResultType, Sel,
ObjCSuper, ObjCTypes.SuperPtrCTy,
- true, CallArgs, Method, ObjCTypes)
- : EmitMessageSend(CGF, Return, ResultType, Sel,
+ true, CallArgs, Method)
+ : EmitMessageSend(CGF, Return, ResultType,
+ EmitSelector(CGF.Builder, Sel),
ObjCSuper, ObjCTypes.SuperPtrCTy,
- true, CallArgs, Method);
+ true, CallArgs, Method, ObjCTypes);
}
llvm::Value *CGObjCNonFragileABIMac::EmitSelector(CGBuilderTy &Builder,
diff --git a/lib/CodeGen/CGObjCRuntime.cpp b/lib/CodeGen/CGObjCRuntime.cpp
index 3d854d4..21150f1 100644
--- a/lib/CodeGen/CGObjCRuntime.cpp
+++ b/lib/CodeGen/CGObjCRuntime.cpp
@@ -165,9 +165,9 @@ namespace {
void CGObjCRuntime::EmitTryCatchStmt(CodeGenFunction &CGF,
const ObjCAtTryStmt &S,
- llvm::Function *beginCatchFn,
- llvm::Function *endCatchFn,
- llvm::Function *exceptionRethrowFn) {
+ llvm::Constant *beginCatchFn,
+ llvm::Constant *endCatchFn,
+ llvm::Constant *exceptionRethrowFn) {
// Jump destination for falling out of catch bodies.
CodeGenFunction::JumpDest Cont;
if (S.getNumCatchStmts())
@@ -233,6 +233,8 @@ void CGObjCRuntime::EmitTryCatchStmt(CodeGenFunction &CGF,
cast<llvm::CallInst>(Exn)->setDoesNotThrow();
}
+ CodeGenFunction::RunCleanupsScope cleanups(CGF);
+
if (endCatchFn) {
// Add a cleanup to leave the catch.
bool EndCatchMightThrow = (Handler.Variable == 0);
@@ -255,9 +257,8 @@ void CGObjCRuntime::EmitTryCatchStmt(CodeGenFunction &CGF,
CGF.EmitStmt(Handler.Body);
CGF.ObjCEHValueStack.pop_back();
- // Leave the earlier cleanup.
- if (endCatchFn)
- CGF.PopCleanupBlock();
+ // Leave any cleanups associated with the catch.
+ cleanups.ForceCleanup();
CGF.EmitBranchThroughCleanup(Cont);
}
diff --git a/lib/CodeGen/CGObjCRuntime.h b/lib/CodeGen/CGObjCRuntime.h
index 0cc2d82..866d5d8 100644
--- a/lib/CodeGen/CGObjCRuntime.h
+++ b/lib/CodeGen/CGObjCRuntime.h
@@ -95,9 +95,9 @@ protected:
/// thrown object directly.
void EmitTryCatchStmt(CodeGenFunction &CGF,
const ObjCAtTryStmt &S,
- llvm::Function *beginCatchFn,
- llvm::Function *endCatchFn,
- llvm::Function *exceptionRethrowFn);
+ llvm::Constant *beginCatchFn,
+ llvm::Constant *endCatchFn,
+ llvm::Constant *exceptionRethrowFn);
/// Emits an @synchronize() statement, using the syncEnterFn and syncExitFn
/// arguments as the functions called to lock and unlock the object. This
/// function can be called by subclasses that use zero-cost exception
@@ -243,6 +243,7 @@ public:
llvm::Value *Size) = 0;
virtual llvm::Constant *BuildGCBlockLayout(CodeGen::CodeGenModule &CGM,
const CodeGen::CGBlockInfo &blockInfo) = 0;
+ virtual llvm::GlobalVariable *GetClassGlobal(const std::string &Name) = 0;
};
/// Creates an instance of an Objective-C runtime class.
diff --git a/lib/CodeGen/CGRecordLayoutBuilder.cpp b/lib/CodeGen/CGRecordLayoutBuilder.cpp
index a4ac390..0d72f85 100644
--- a/lib/CodeGen/CGRecordLayoutBuilder.cpp
+++ b/lib/CodeGen/CGRecordLayoutBuilder.cpp
@@ -234,7 +234,7 @@ CGBitFieldInfo CGBitFieldInfo::MakeInfo(CodeGenTypes &Types,
CharUnits::fromQuantity(Types.getTargetData().getTypeAllocSize(Ty));
uint64_t TypeSizeInBits = Types.getContext().toBits(TypeSizeInBytes);
- bool IsSigned = FD->getType()->isSignedIntegerType();
+ bool IsSigned = FD->getType()->isSignedIntegerOrEnumerationType();
if (FieldSize > TypeSizeInBits) {
// We have a wide bit-field. The extra bits are only used for padding, so
@@ -753,8 +753,7 @@ bool CGRecordLayoutBuilder::LayoutFields(const RecordDecl *D) {
// Zero-length bitfields following non-bitfield members are
// ignored:
const FieldDecl *FD = (*Field);
- if (Types.getContext().ZeroBitfieldFollowsNonBitfield(FD, LastFD) ||
- Types.getContext().ZeroBitfieldFollowsBitfield(FD, LastFD)) {
+ if (Types.getContext().ZeroBitfieldFollowsNonBitfield(FD, LastFD)) {
--FieldNo;
continue;
}
@@ -997,8 +996,7 @@ CGRecordLayout *CodeGenTypes::ComputeRecordLayout(const RecordDecl *D) {
if (IsMsStruct) {
// Zero-length bitfields following non-bitfield members are
// ignored:
- if (getContext().ZeroBitfieldFollowsNonBitfield(FD, LastFD) ||
- getContext().ZeroBitfieldFollowsBitfield(FD, LastFD)) {
+ if (getContext().ZeroBitfieldFollowsNonBitfield(FD, LastFD)) {
--i;
continue;
}
diff --git a/lib/CodeGen/CGStmt.cpp b/lib/CodeGen/CGStmt.cpp
index 99bc3f4..a982621 100644
--- a/lib/CodeGen/CGStmt.cpp
+++ b/lib/CodeGen/CGStmt.cpp
@@ -773,10 +773,8 @@ void CodeGenFunction::EmitReturnStmt(const ReturnStmt &S) {
void CodeGenFunction::EmitDeclStmt(const DeclStmt &S) {
// As long as debug info is modeled with instructions, we have to ensure we
// have a place to insert here and write the stop point here.
- if (getDebugInfo()) {
- EnsureInsertPoint();
+ if (getDebugInfo() && HaveInsertPoint())
EmitStopPoint(&S);
- }
for (DeclStmt::const_decl_iterator I = S.decl_begin(), E = S.decl_end();
I != E; ++I)
@@ -999,7 +997,7 @@ static CSFC_Result CollectStatementsForCase(const Stmt *S,
// If we're looking for the case, just see if we can skip each of the
// substatements.
for (; Case && I != E; ++I) {
- HadSkippedDecl |= isa<DeclStmt>(I);
+ HadSkippedDecl |= isa<DeclStmt>(*I);
switch (CollectStatementsForCase(*I, Case, FoundCase, ResultStmts)) {
case CSFC_Failure: return CSFC_Failure;
@@ -1224,7 +1222,7 @@ SimplifyConstraint(const char *Constraint, const TargetInfo &Target,
while (*Constraint) {
switch (*Constraint) {
default:
- Result += Target.convertConstraint(*Constraint);
+ Result += Target.convertConstraint(Constraint);
break;
// Ignore these
case '*':
@@ -1422,8 +1420,8 @@ void CodeGenFunction::EmitAsmStmt(const AsmStmt &S) {
const Expr *OutExpr = S.getOutputExpr(i);
OutExpr = OutExpr->IgnoreParenNoopCasts(getContext());
- OutputConstraint = AddVariableConstraints(OutputConstraint, *OutExpr, Target,
- CGM, S);
+ OutputConstraint = AddVariableConstraints(OutputConstraint, *OutExpr,
+ Target, CGM, S);
LValue Dest = EmitLValue(OutExpr);
if (!Constraints.empty())
diff --git a/lib/CodeGen/CGVTT.cpp b/lib/CodeGen/CGVTT.cpp
index a6849f8..aefc41e 100644
--- a/lib/CodeGen/CGVTT.cpp
+++ b/lib/CodeGen/CGVTT.cpp
@@ -411,6 +411,8 @@ llvm::GlobalVariable *CodeGenVTables::GetAddrOfVTT(const CXXRecordDecl *RD) {
Out.flush();
llvm::StringRef Name = OutName.str();
+ ComputeVTableRelatedInformation(RD, /*VTableRequired=*/true);
+
VTTBuilder Builder(CGM, RD, /*GenerateDefinition=*/false);
const llvm::Type *Int8PtrTy =
diff --git a/lib/CodeGen/CGVTables.cpp b/lib/CodeGen/CGVTables.cpp
index 581467c..9ac5e67 100644
--- a/lib/CodeGen/CGVTables.cpp
+++ b/lib/CodeGen/CGVTables.cpp
@@ -21,6 +21,7 @@
#include "llvm/ADT/SetVector.h"
#include "llvm/Support/Compiler.h"
#include "llvm/Support/Format.h"
+#include "llvm/Transforms/Utils/Cloning.h"
#include <algorithm>
#include <cstdio>
@@ -2636,6 +2637,131 @@ static bool similar(const ABIArgInfo &infoL, CanQualType typeL,
}
#endif
+static RValue PerformReturnAdjustment(CodeGenFunction &CGF,
+ QualType ResultType, RValue RV,
+ const ThunkInfo &Thunk) {
+ // Emit the return adjustment.
+ bool NullCheckValue = !ResultType->isReferenceType();
+
+ llvm::BasicBlock *AdjustNull = 0;
+ llvm::BasicBlock *AdjustNotNull = 0;
+ llvm::BasicBlock *AdjustEnd = 0;
+
+ llvm::Value *ReturnValue = RV.getScalarVal();
+
+ if (NullCheckValue) {
+ AdjustNull = CGF.createBasicBlock("adjust.null");
+ AdjustNotNull = CGF.createBasicBlock("adjust.notnull");
+ AdjustEnd = CGF.createBasicBlock("adjust.end");
+
+ llvm::Value *IsNull = CGF.Builder.CreateIsNull(ReturnValue);
+ CGF.Builder.CreateCondBr(IsNull, AdjustNull, AdjustNotNull);
+ CGF.EmitBlock(AdjustNotNull);
+ }
+
+ ReturnValue = PerformTypeAdjustment(CGF, ReturnValue,
+ Thunk.Return.NonVirtual,
+ Thunk.Return.VBaseOffsetOffset);
+
+ if (NullCheckValue) {
+ CGF.Builder.CreateBr(AdjustEnd);
+ CGF.EmitBlock(AdjustNull);
+ CGF.Builder.CreateBr(AdjustEnd);
+ CGF.EmitBlock(AdjustEnd);
+
+ llvm::PHINode *PHI = CGF.Builder.CreatePHI(ReturnValue->getType(), 2);
+ PHI->addIncoming(ReturnValue, AdjustNotNull);
+ PHI->addIncoming(llvm::Constant::getNullValue(ReturnValue->getType()),
+ AdjustNull);
+ ReturnValue = PHI;
+ }
+
+ return RValue::get(ReturnValue);
+}
+
+// This function does roughly the same thing as GenerateThunk, but in a
+// very different way, so that va_start and va_end work correctly.
+// FIXME: This function assumes "this" is the first non-sret LLVM argument of
+// a function, and that there is an alloca built in the entry block
+// for all accesses to "this".
+// FIXME: This function assumes there is only one "ret" statement per function.
+// FIXME: Cloning isn't correct in the presence of indirect goto!
+// FIXME: This implementation of thunks bloats codesize by duplicating the
+// function definition. There are alternatives:
+// 1. Add some sort of stub support to LLVM for cases where we can
+// do a this adjustment, then a sibcall.
+// 2. We could transform the definition to take a va_list instead of an
+// actual variable argument list, then have the thunks (including a
+// no-op thunk for the regular definition) call va_start/va_end.
+// There's a bit of per-call overhead for this solution, but it's
+// better for codesize if the definition is long.
+void CodeGenFunction::GenerateVarArgsThunk(
+ llvm::Function *Fn,
+ const CGFunctionInfo &FnInfo,
+ GlobalDecl GD, const ThunkInfo &Thunk) {
+ const CXXMethodDecl *MD = cast<CXXMethodDecl>(GD.getDecl());
+ const FunctionProtoType *FPT = MD->getType()->getAs<FunctionProtoType>();
+ QualType ResultType = FPT->getResultType();
+
+ // Get the original function
+ const llvm::Type *Ty =
+ CGM.getTypes().GetFunctionType(FnInfo, /*IsVariadic*/true);
+ llvm::Value *Callee = CGM.GetAddrOfFunction(GD, Ty, /*ForVTable=*/true);
+ llvm::Function *BaseFn = cast<llvm::Function>(Callee);
+
+ // Clone to thunk.
+ llvm::Function *NewFn = llvm::CloneFunction(BaseFn);
+ CGM.getModule().getFunctionList().push_back(NewFn);
+ Fn->replaceAllUsesWith(NewFn);
+ NewFn->takeName(Fn);
+ Fn->eraseFromParent();
+ Fn = NewFn;
+
+ // "Initialize" CGF (minimally).
+ CurFn = Fn;
+
+ // Get the "this" value
+ llvm::Function::arg_iterator AI = Fn->arg_begin();
+ if (CGM.ReturnTypeUsesSRet(FnInfo))
+ ++AI;
+
+ // Find the first store of "this", which will be to the alloca associated
+ // with "this".
+ llvm::Value *ThisPtr = &*AI;
+ llvm::BasicBlock *EntryBB = Fn->begin();
+ llvm::Instruction *ThisStore = 0;
+ for (llvm::BasicBlock::iterator I = EntryBB->begin(), E = EntryBB->end();
+ I != E; I++) {
+ if (isa<llvm::StoreInst>(I) && I->getOperand(0) == ThisPtr) {
+ ThisStore = cast<llvm::StoreInst>(I);
+ break;
+ }
+ }
+ assert(ThisStore && "Store of this should be in entry block?");
+ // Adjust "this", if necessary.
+ Builder.SetInsertPoint(ThisStore);
+ llvm::Value *AdjustedThisPtr =
+ PerformTypeAdjustment(*this, ThisPtr,
+ Thunk.This.NonVirtual,
+ Thunk.This.VCallOffsetOffset);
+ ThisStore->setOperand(0, AdjustedThisPtr);
+
+ if (!Thunk.Return.isEmpty()) {
+ // Fix up the returned value, if necessary.
+ for (llvm::Function::iterator I = Fn->begin(), E = Fn->end(); I != E; I++) {
+ llvm::Instruction *T = I->getTerminator();
+ if (isa<llvm::ReturnInst>(T)) {
+ RValue RV = RValue::get(T->getOperand(0));
+ T->eraseFromParent();
+ Builder.SetInsertPoint(&*I);
+ RV = PerformReturnAdjustment(*this, ResultType, RV, Thunk);
+ Builder.CreateRet(RV.getScalarVal());
+ break;
+ }
+ }
+ }
+}
+
void CodeGenFunction::GenerateThunk(llvm::Function *Fn,
const CGFunctionInfo &FnInfo,
GlobalDecl GD, const ThunkInfo &Thunk) {
@@ -2715,45 +2841,8 @@ void CodeGenFunction::GenerateThunk(llvm::Function *Fn,
// Now emit our call.
RValue RV = EmitCall(FnInfo, Callee, Slot, CallArgs, MD);
- if (!Thunk.Return.isEmpty()) {
- // Emit the return adjustment.
- bool NullCheckValue = !ResultType->isReferenceType();
-
- llvm::BasicBlock *AdjustNull = 0;
- llvm::BasicBlock *AdjustNotNull = 0;
- llvm::BasicBlock *AdjustEnd = 0;
-
- llvm::Value *ReturnValue = RV.getScalarVal();
-
- if (NullCheckValue) {
- AdjustNull = createBasicBlock("adjust.null");
- AdjustNotNull = createBasicBlock("adjust.notnull");
- AdjustEnd = createBasicBlock("adjust.end");
-
- llvm::Value *IsNull = Builder.CreateIsNull(ReturnValue);
- Builder.CreateCondBr(IsNull, AdjustNull, AdjustNotNull);
- EmitBlock(AdjustNotNull);
- }
-
- ReturnValue = PerformTypeAdjustment(*this, ReturnValue,
- Thunk.Return.NonVirtual,
- Thunk.Return.VBaseOffsetOffset);
-
- if (NullCheckValue) {
- Builder.CreateBr(AdjustEnd);
- EmitBlock(AdjustNull);
- Builder.CreateBr(AdjustEnd);
- EmitBlock(AdjustEnd);
-
- llvm::PHINode *PHI = Builder.CreatePHI(ReturnValue->getType(), 2);
- PHI->addIncoming(ReturnValue, AdjustNotNull);
- PHI->addIncoming(llvm::Constant::getNullValue(ReturnValue->getType()),
- AdjustNull);
- ReturnValue = PHI;
- }
-
- RV = RValue::get(ReturnValue);
- }
+ if (!Thunk.Return.isEmpty())
+ RV = PerformReturnAdjustment(*this, ResultType, RV, Thunk);
if (!ResultType->isVoidType() && Slot.isNull())
CGM.getCXXABI().EmitReturnFromThunk(*this, RV, ResultType);
@@ -2823,8 +2912,18 @@ void CodeGenVTables::EmitThunk(GlobalDecl GD, const ThunkInfo &Thunk,
return;
}
- // Actually generate the thunk body.
- CodeGenFunction(CGM).GenerateThunk(ThunkFn, FnInfo, GD, Thunk);
+ if (ThunkFn->isVarArg()) {
+ // Varargs thunks are special; we can't just generate a call because
+ // we can't copy the varargs. Our implementation is rather
+ // expensive/sucky at the moment, so don't generate the thunk unless
+ // we have to.
+ // FIXME: Do something better here; GenerateVarArgsThunk is extremely ugly.
+ if (!UseAvailableExternallyLinkage)
+ CodeGenFunction(CGM).GenerateVarArgsThunk(ThunkFn, FnInfo, GD, Thunk);
+ } else {
+ // Normal thunk body generation.
+ CodeGenFunction(CGM).GenerateThunk(ThunkFn, FnInfo, GD, Thunk);
+ }
if (UseAvailableExternallyLinkage)
ThunkFn->setLinkage(llvm::GlobalValue::AvailableExternallyLinkage);
@@ -3076,7 +3175,7 @@ llvm::GlobalVariable *CodeGenVTables::GetAddrOfVTable(const CXXRecordDecl *RD) {
Out.flush();
llvm::StringRef Name = OutName.str();
- ComputeVTableRelatedInformation(RD, true);
+ ComputeVTableRelatedInformation(RD, /*VTableRequired=*/true);
const llvm::Type *Int8PtrTy = llvm::Type::getInt8PtrTy(CGM.getLLVMContext());
llvm::ArrayType *ArrayType =
diff --git a/lib/CodeGen/CodeGenFunction.cpp b/lib/CodeGen/CodeGenFunction.cpp
index 626c2b0..150cb69 100644
--- a/lib/CodeGen/CodeGenFunction.cpp
+++ b/lib/CodeGen/CodeGenFunction.cpp
@@ -33,9 +33,9 @@ CodeGenFunction::CodeGenFunction(CodeGenModule &cgm)
Target(CGM.getContext().Target), Builder(cgm.getModule().getContext()),
BlockInfo(0), BlockPointer(0),
NormalCleanupDest(0), EHCleanupDest(0), NextCleanupDestIndex(1),
- ExceptionSlot(0), DebugInfo(0), DisableDebugInfo(false), IndirectBranch(0),
- SwitchInsn(0), CaseRangeBlock(0),
- DidCallStackSave(false), UnreachableBlock(0),
+ ExceptionSlot(0), EHSelectorSlot(0),
+ DebugInfo(0), DisableDebugInfo(false), DidCallStackSave(false),
+ IndirectBranch(0), SwitchInsn(0), CaseRangeBlock(0), UnreachableBlock(0),
CXXThisDecl(0), CXXThisValue(0), CXXVTTDecl(0), CXXVTTValue(0),
OutermostConditional(0), TerminateLandingPad(0), TerminateHandler(0),
TrapBB(0) {
@@ -44,10 +44,6 @@ CodeGenFunction::CodeGenFunction(CodeGenModule &cgm)
CGM.getCXXABI().getMangleContext().startNewFunction();
}
-ASTContext &CodeGenFunction::getContext() const {
- return CGM.getContext();
-}
-
const llvm::Type *CodeGenFunction::ConvertTypeForMem(QualType T) {
return CGM.getTypes().ConvertTypeForMem(T);
@@ -57,9 +53,41 @@ const llvm::Type *CodeGenFunction::ConvertType(QualType T) {
return CGM.getTypes().ConvertType(T);
}
-bool CodeGenFunction::hasAggregateLLVMType(QualType T) {
- return T->isRecordType() || T->isArrayType() || T->isAnyComplexType() ||
- T->isObjCObjectType();
+bool CodeGenFunction::hasAggregateLLVMType(QualType type) {
+ switch (type.getCanonicalType()->getTypeClass()) {
+#define TYPE(name, parent)
+#define ABSTRACT_TYPE(name, parent)
+#define NON_CANONICAL_TYPE(name, parent) case Type::name:
+#define DEPENDENT_TYPE(name, parent) case Type::name:
+#define NON_CANONICAL_UNLESS_DEPENDENT_TYPE(name, parent) case Type::name:
+#include "clang/AST/TypeNodes.def"
+ llvm_unreachable("non-canonical or dependent type in IR-generation");
+
+ case Type::Builtin:
+ case Type::Pointer:
+ case Type::BlockPointer:
+ case Type::LValueReference:
+ case Type::RValueReference:
+ case Type::MemberPointer:
+ case Type::Vector:
+ case Type::ExtVector:
+ case Type::FunctionProto:
+ case Type::FunctionNoProto:
+ case Type::Enum:
+ case Type::ObjCObjectPointer:
+ return false;
+
+ // Complexes, arrays, records, and Objective-C objects.
+ case Type::Complex:
+ case Type::ConstantArray:
+ case Type::IncompleteArray:
+ case Type::VariableArray:
+ case Type::Record:
+ case Type::ObjCObject:
+ case Type::ObjCInterface:
+ return true;
+ }
+ llvm_unreachable("unknown type kind!");
}
void CodeGenFunction::EmitReturnBlock() {
@@ -168,7 +196,7 @@ void CodeGenFunction::FinishFunction(SourceLocation EndLoc) {
bool CodeGenFunction::ShouldInstrumentFunction() {
if (!CGM.getCodeGenOpts().InstrumentFunctions)
return false;
- if (CurFuncDecl->hasAttr<NoInstrumentFunctionAttr>())
+ if (!CurFuncDecl || CurFuncDecl->hasAttr<NoInstrumentFunctionAttr>())
return false;
return true;
}
@@ -177,16 +205,12 @@ bool CodeGenFunction::ShouldInstrumentFunction() {
/// instrumentation function with the current function and the call site, if
/// function instrumentation is enabled.
void CodeGenFunction::EmitFunctionInstrumentation(const char *Fn) {
- const llvm::PointerType *PointerTy;
- const llvm::FunctionType *FunctionTy;
- std::vector<const llvm::Type*> ProfileFuncArgs;
-
// void __cyg_profile_func_{enter,exit} (void *this_fn, void *call_site);
- PointerTy = Int8PtrTy;
- ProfileFuncArgs.push_back(PointerTy);
- ProfileFuncArgs.push_back(PointerTy);
- FunctionTy = llvm::FunctionType::get(llvm::Type::getVoidTy(getLLVMContext()),
- ProfileFuncArgs, false);
+ const llvm::PointerType *PointerTy = Int8PtrTy;
+ const llvm::Type *ProfileFuncArgs[] = { PointerTy, PointerTy };
+ const llvm::FunctionType *FunctionTy =
+ llvm::FunctionType::get(llvm::Type::getVoidTy(getLLVMContext()),
+ ProfileFuncArgs, false);
llvm::Constant *F = CGM.CreateRuntimeFunction(FunctionTy, Fn);
llvm::CallInst *CallSite = Builder.CreateCall(
diff --git a/lib/CodeGen/CodeGenFunction.h b/lib/CodeGen/CodeGenFunction.h
index 169c576..bb8fd8e 100644
--- a/lib/CodeGen/CodeGenFunction.h
+++ b/lib/CodeGen/CodeGenFunction.h
@@ -603,6 +603,10 @@ public:
/// exception pointer into this alloca.
llvm::Value *ExceptionSlot;
+ /// The selector slot. Under the MandatoryCleanup model, all
+ /// landing pads write the current selector value into this alloca.
+ llvm::AllocaInst *EHSelectorSlot;
+
/// Emits a landing pad for the current EH stack.
llvm::BasicBlock *EmitLandingPad();
@@ -951,6 +955,10 @@ private:
CGDebugInfo *DebugInfo;
bool DisableDebugInfo;
+ /// DidCallStackSave - Whether llvm.stacksave has been called. Used to avoid
+ /// calling llvm.stacksave for multiple VLAs in the same scope.
+ bool DidCallStackSave;
+
/// IndirectBranch - The first time an indirect goto is seen we create a block
/// with an indirect branch. Every time we see the address of a label taken,
/// we add the label to the indirect goto. Every subsequent indirect goto is
@@ -997,10 +1005,6 @@ private:
// enter/leave scopes.
llvm::DenseMap<const Expr*, llvm::Value*> VLASizeMap;
- /// DidCallStackSave - Whether llvm.stacksave has been called. Used to avoid
- /// calling llvm.stacksave for multiple VLAs in the same scope.
- bool DidCallStackSave;
-
/// A block containing a single 'unreachable' instruction. Created
/// lazily by getUnreachableBlock().
llvm::BasicBlock *UnreachableBlock;
@@ -1035,7 +1039,7 @@ public:
CodeGenFunction(CodeGenModule &cgm);
CodeGenTypes &getTypes() const { return CGM.getTypes(); }
- ASTContext &getContext() const;
+ ASTContext &getContext() const { return CGM.getContext(); }
CGDebugInfo *getDebugInfo() {
if (DisableDebugInfo)
return NULL;
@@ -1050,6 +1054,7 @@ public:
/// Returns a pointer to the function's exception object slot, which
/// is assigned in every landing pad.
llvm::Value *getExceptionSlot();
+ llvm::Value *getEHSelectorSlot();
llvm::Value *getNormalCleanupDestSlot();
llvm::Value *getEHCleanupDestSlot();
@@ -1076,7 +1081,8 @@ public:
void GenerateObjCMethod(const ObjCMethodDecl *OMD);
void StartObjCMethod(const ObjCMethodDecl *MD,
- const ObjCContainerDecl *CD);
+ const ObjCContainerDecl *CD,
+ SourceLocation StartLoc);
/// GenerateObjCGetter - Synthesize an Objective-C property getter function.
void GenerateObjCGetter(ObjCImplementationDecl *IMP,
@@ -1157,6 +1163,9 @@ public:
void GenerateThunk(llvm::Function *Fn, const CGFunctionInfo &FnInfo,
GlobalDecl GD, const ThunkInfo &Thunk);
+ void GenerateVarArgsThunk(llvm::Function *Fn, const CGFunctionInfo &FnInfo,
+ GlobalDecl GD, const ThunkInfo &Thunk);
+
void EmitCtorPrologue(const CXXConstructorDecl *CD, CXXCtorType Type,
FunctionArgList &Args);
@@ -1701,6 +1710,7 @@ public:
void EmitObjCAtThrowStmt(const ObjCAtThrowStmt &S);
void EmitObjCAtSynchronizedStmt(const ObjCAtSynchronizedStmt &S);
+ llvm::Constant *getUnwindResumeFn();
llvm::Constant *getUnwindResumeOrRethrowFn();
void EnterCXXTryStmt(const CXXTryStmt &S, bool IsFnTryBlock = false);
void ExitCXXTryStmt(const CXXTryStmt &S, bool IsFnTryBlock = false);
@@ -1915,6 +1925,9 @@ public:
RValue EmitCXXMemberPointerCallExpr(const CXXMemberCallExpr *E,
ReturnValueSlot ReturnValue);
+ llvm::Value *EmitCXXOperatorMemberCallee(const CXXOperatorCallExpr *E,
+ const CXXMethodDecl *MD,
+ llvm::Value *This);
RValue EmitCXXOperatorMemberCallExpr(const CXXOperatorCallExpr *E,
const CXXMethodDecl *MD,
ReturnValueSlot ReturnValue);
diff --git a/lib/CodeGen/CodeGenModule.cpp b/lib/CodeGen/CodeGenModule.cpp
index 83e927f..7a1a968 100644
--- a/lib/CodeGen/CodeGenModule.cpp
+++ b/lib/CodeGen/CodeGenModule.cpp
@@ -90,9 +90,10 @@ CodeGenModule::CodeGenModule(ASTContext &C, const CodeGenOptions &CGO,
// Initialize the type cache.
llvm::LLVMContext &LLVMContext = M.getContext();
- Int8Ty = llvm::Type::getInt8Ty(LLVMContext);
- Int32Ty = llvm::Type::getInt32Ty(LLVMContext);
- Int64Ty = llvm::Type::getInt64Ty(LLVMContext);
+ VoidTy = llvm::Type::getVoidTy(LLVMContext);
+ Int8Ty = llvm::Type::getInt8Ty(LLVMContext);
+ Int32Ty = llvm::Type::getInt32Ty(LLVMContext);
+ Int64Ty = llvm::Type::getInt64Ty(LLVMContext);
PointerWidthInBits = C.Target.getPointerWidth(0);
PointerAlignInBytes =
C.toCharUnitsFromBits(C.Target.getPointerAlign(0)).getQuantity();
@@ -132,6 +133,9 @@ void CodeGenModule::Release() {
if (getCodeGenOpts().EmitDeclMetadata)
EmitDeclMetadata();
+
+ if (getCodeGenOpts().EmitGcovArcs || getCodeGenOpts().EmitGcovNotes)
+ EmitCoverageFile();
}
void CodeGenModule::UpdateCompletedType(const TagDecl *TD) {
@@ -339,8 +343,7 @@ void CodeGenModule::AddGlobalDtor(llvm::Function * Dtor, int Priority) {
void CodeGenModule::EmitCtorList(const CtorList &Fns, const char *GlobalName) {
// Ctor function type is void()*.
- llvm::FunctionType* CtorFTy =
- llvm::FunctionType::get(llvm::Type::getVoidTy(VMContext), false);
+ llvm::FunctionType* CtorFTy = llvm::FunctionType::get(VoidTy, false);
llvm::Type *CtorPFTy = llvm::PointerType::getUnqual(CtorFTy);
// Get the type of a ctor entry, { i32, void ()* }.
@@ -449,6 +452,9 @@ void CodeGenModule::SetLLVMFunctionAttributes(const Decl *D,
void CodeGenModule::SetLLVMFunctionAttributesForDefinition(const Decl *D,
llvm::Function *F) {
+ if (CodeGenOpts.UnwindTables)
+ F->setHasUWTable();
+
if (!Features.Exceptions && !Features.ObjCNonFragileABI)
F->addFnAttr(llvm::Attribute::NoUnwind);
@@ -724,7 +730,7 @@ void CodeGenModule::EmitGlobal(GlobalDecl GD) {
}
// Forward declarations are emitted lazily on first use.
- if (!FD->isThisDeclarationADefinition())
+ if (!FD->doesThisDeclarationHaveABody())
return;
} else {
const VarDecl *VD = cast<VarDecl>(Global);
@@ -790,14 +796,19 @@ void CodeGenModule::EmitGlobalDefinition(GlobalDecl GD) {
return;
if (const CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(D)) {
+ // Make sure to emit the definition(s) before we emit the thunks.
+ // This is necessary for the generation of certain thunks.
+ if (const CXXConstructorDecl *CD = dyn_cast<CXXConstructorDecl>(Method))
+ EmitCXXConstructor(CD, GD.getCtorType());
+ else if (const CXXDestructorDecl *DD =dyn_cast<CXXDestructorDecl>(Method))
+ EmitCXXDestructor(DD, GD.getDtorType());
+ else
+ EmitGlobalFunctionDefinition(GD);
+
if (Method->isVirtual())
getVTables().EmitThunks(GD);
- if (const CXXConstructorDecl *CD = dyn_cast<CXXConstructorDecl>(Method))
- return EmitCXXConstructor(CD, GD.getCtorType());
-
- if (const CXXDestructorDecl *DD = dyn_cast<CXXDestructorDecl>(Method))
- return EmitCXXDestructor(DD, GD.getDtorType());
+ return;
}
return EmitGlobalFunctionDefinition(GD);
@@ -848,7 +859,7 @@ CodeGenModule::GetOrCreateLLVMFunction(llvm::StringRef MangledName,
if (isa<llvm::FunctionType>(Ty)) {
FTy = cast<llvm::FunctionType>(Ty);
} else {
- FTy = llvm::FunctionType::get(llvm::Type::getVoidTy(VMContext), false);
+ FTy = llvm::FunctionType::get(VoidTy, false);
IsIncompleteFunction = true;
}
@@ -889,7 +900,7 @@ CodeGenModule::GetOrCreateLLVMFunction(llvm::StringRef MangledName,
assert(FD->isUsed() && "Sema didn't mark implicit function as used!");
DeferredDeclsToEmit.push_back(D.getWithDecl(FD));
break;
- } else if (FD->isThisDeclarationADefinition()) {
+ } else if (FD->doesThisDeclarationHaveABody()) {
DeferredDeclsToEmit.push_back(D.getWithDecl(FD));
break;
}
@@ -930,14 +941,19 @@ CodeGenModule::CreateRuntimeFunction(const llvm::FunctionType *FTy,
return GetOrCreateLLVMFunction(Name, FTy, GlobalDecl(), /*ForVTable=*/false);
}
-static bool DeclIsConstantGlobal(ASTContext &Context, const VarDecl *D) {
+static bool DeclIsConstantGlobal(ASTContext &Context, const VarDecl *D,
+ bool ConstantInit) {
if (!D->getType().isConstant(Context) && !D->getType()->isReferenceType())
return false;
- if (Context.getLangOptions().CPlusPlus &&
- Context.getBaseElementType(D->getType())->getAs<RecordType>()) {
- // FIXME: We should do something fancier here!
- return false;
+
+ if (Context.getLangOptions().CPlusPlus) {
+ if (const RecordType *Record
+ = Context.getBaseElementType(D->getType())->getAs<RecordType>())
+ return ConstantInit &&
+ cast<CXXRecordDecl>(Record->getDecl())->isPOD() &&
+ !cast<CXXRecordDecl>(Record->getDecl())->hasMutableFields();
}
+
return true;
}
@@ -994,7 +1010,7 @@ CodeGenModule::GetOrCreateLLVMGlobal(llvm::StringRef MangledName,
if (D) {
// FIXME: This code is overly simple and should be merged with other global
// handling.
- GV->setConstant(DeclIsConstantGlobal(Context, D));
+ GV->setConstant(DeclIsConstantGlobal(Context, D, false));
// Set linkage and visibility in case we never see a definition.
NamedDecl::LinkageInfo LV = D->getLinkageAndVisibility();
@@ -1109,7 +1125,7 @@ void CodeGenModule::EmitVTable(CXXRecordDecl *Class, bool DefinitionRequired) {
llvm::GlobalVariable::LinkageTypes
CodeGenModule::getVTableLinkage(const CXXRecordDecl *RD) {
- if (RD->isInAnonymousNamespace() || !RD->hasLinkage())
+ if (RD->getLinkage() != ExternalLinkage)
return llvm::GlobalVariable::InternalLinkage;
if (const CXXMethodDecl *KeyFunction
@@ -1276,7 +1292,7 @@ void CodeGenModule::EmitGlobalVarDefinition(const VarDecl *D) {
// If it is safe to mark the global 'constant', do so now.
GV->setConstant(false);
- if (!NonConstInit && DeclIsConstantGlobal(Context, D))
+ if (!NonConstInit && DeclIsConstantGlobal(Context, D, true))
GV->setConstant(true);
GV->setAlignment(getContext().getDeclAlign(D).getQuantity());
@@ -1561,14 +1577,24 @@ llvm::Value *CodeGenModule::getBuiltinLibFunction(const FunctionDecl *FD,
"isn't a lib fn");
// Get the name, skip over the __builtin_ prefix (if necessary).
- const char *Name = Context.BuiltinInfo.GetName(BuiltinID);
- if (Context.BuiltinInfo.isLibFunction(BuiltinID))
- Name += 10;
+ llvm::StringRef Name;
+ GlobalDecl D(FD);
+
+ // If the builtin has been declared explicitly with an assembler label,
+ // use the mangled name. This differs from the plain label on platforms
+ // that prefix labels.
+ if (FD->hasAttr<AsmLabelAttr>())
+ Name = getMangledName(D);
+ else if (Context.BuiltinInfo.isLibFunction(BuiltinID))
+ Name = Context.BuiltinInfo.GetName(BuiltinID) + 10;
+ else
+ Name = Context.BuiltinInfo.GetName(BuiltinID);
+
const llvm::FunctionType *Ty =
cast<llvm::FunctionType>(getTypes().ConvertType(FD->getType()));
- return GetOrCreateLLVMFunction(Name, Ty, GlobalDecl(FD), /*ForVTable=*/false);
+ return GetOrCreateLLVMFunction(Name, Ty, D, /*ForVTable=*/false);
}
llvm::Function *CodeGenModule::getIntrinsic(unsigned IID,const llvm::Type **Tys,
@@ -1628,6 +1654,16 @@ GetConstantCFStringEntry(llvm::StringMap<llvm::Constant*> &Map,
return Map.GetOrCreateValue(llvm::StringRef(AsBytes.data(), AsBytes.size()));
}
+static llvm::StringMapEntry<llvm::Constant*> &
+GetConstantStringEntry(llvm::StringMap<llvm::Constant*> &Map,
+ const StringLiteral *Literal,
+ unsigned &StringLength)
+{
+ llvm::StringRef String = Literal->getString();
+ StringLength = String.size();
+ return Map.GetOrCreateValue(String);
+}
+
llvm::Constant *
CodeGenModule::GetAddrOfConstantCFString(const StringLiteral *Literal) {
unsigned StringLength = 0;
@@ -1721,11 +1757,8 @@ CodeGenModule::GetAddrOfConstantCFString(const StringLiteral *Literal) {
llvm::Constant *
CodeGenModule::GetAddrOfConstantString(const StringLiteral *Literal) {
unsigned StringLength = 0;
- bool isUTF16 = false;
llvm::StringMapEntry<llvm::Constant*> &Entry =
- GetConstantCFStringEntry(CFConstantStringMap, Literal,
- getTargetData().isLittleEndian(),
- isUTF16, StringLength);
+ GetConstantStringEntry(CFConstantStringMap, Literal, StringLength);
if (llvm::Constant *C = Entry.getValue())
return C;
@@ -1738,24 +1771,26 @@ CodeGenModule::GetAddrOfConstantString(const StringLiteral *Literal) {
if (!ConstantStringClassRef) {
std::string StringClass(getLangOptions().ObjCConstantStringClass);
const llvm::Type *Ty = getTypes().ConvertType(getContext().IntTy);
- Ty = llvm::ArrayType::get(Ty, 0);
llvm::Constant *GV;
- if (StringClass.empty())
- GV = CreateRuntimeVariable(Ty,
- Features.ObjCNonFragileABI ?
- "OBJC_CLASS_$_NSConstantString" :
- "_NSConstantStringClassReference");
- else {
- std::string str;
- if (Features.ObjCNonFragileABI)
- str = "OBJC_CLASS_$_" + StringClass;
- else
- str = "_" + StringClass + "ClassReference";
- GV = CreateRuntimeVariable(Ty, str);
+ if (Features.ObjCNonFragileABI) {
+ std::string str =
+ StringClass.empty() ? "OBJC_CLASS_$_NSConstantString"
+ : "OBJC_CLASS_$_" + StringClass;
+ GV = getObjCRuntime().GetClassGlobal(str);
+ // Make sure the result is of the correct type.
+ const llvm::Type *PTy = llvm::PointerType::getUnqual(Ty);
+ ConstantStringClassRef =
+ llvm::ConstantExpr::getBitCast(GV, PTy);
+ } else {
+ std::string str =
+ StringClass.empty() ? "_NSConstantStringClassReference"
+ : "_" + StringClass + "ClassReference";
+ const llvm::Type *PTy = llvm::ArrayType::get(Ty, 0);
+ GV = CreateRuntimeVariable(PTy, str);
+ // Decay array -> ptr
+ ConstantStringClassRef =
+ llvm::ConstantExpr::getGetElementPtr(GV, Zeros, 2);
}
- // Decay array -> ptr
- ConstantStringClassRef =
- llvm::ConstantExpr::getGetElementPtr(GV, Zeros, 2);
}
QualType NSTy = getContext().getNSConstantStringType();
@@ -1773,28 +1808,15 @@ CodeGenModule::GetAddrOfConstantString(const StringLiteral *Literal) {
llvm::GlobalValue::LinkageTypes Linkage;
bool isConstant;
- if (isUTF16) {
- // FIXME: why do utf strings get "_" labels instead of "L" labels?
- Linkage = llvm::GlobalValue::InternalLinkage;
- // Note: -fwritable-strings doesn't make unicode NSStrings writable, but
- // does make plain ascii ones writable.
- isConstant = true;
- } else {
- Linkage = llvm::GlobalValue::PrivateLinkage;
- isConstant = !Features.WritableStrings;
- }
+ Linkage = llvm::GlobalValue::PrivateLinkage;
+ isConstant = !Features.WritableStrings;
llvm::GlobalVariable *GV =
new llvm::GlobalVariable(getModule(), C->getType(), isConstant, Linkage, C,
".str");
GV->setUnnamedAddr(true);
- if (isUTF16) {
- CharUnits Align = getContext().getTypeAlignInChars(getContext().ShortTy);
- GV->setAlignment(Align.getQuantity());
- } else {
- CharUnits Align = getContext().getTypeAlignInChars(getContext().CharTy);
- GV->setAlignment(Align.getQuantity());
- }
+ CharUnits Align = getContext().getTypeAlignInChars(getContext().CharTy);
+ GV->setAlignment(Align.getQuantity());
Fields[1] = llvm::ConstantExpr::getGetElementPtr(GV, Zeros, 2);
// String length.
@@ -1877,6 +1899,7 @@ static llvm::Constant *GenerateStringLiteral(llvm::StringRef str,
new llvm::GlobalVariable(CGM.getModule(), C->getType(), constant,
llvm::GlobalValue::PrivateLinkage,
C, GlobalName);
+ GV->setAlignment(1);
GV->setUnnamedAddr(true);
return GV;
}
@@ -2057,7 +2080,9 @@ void CodeGenModule::EmitTopLevelDecl(Decl *D) {
case Decl::UsingDirective:
case Decl::ClassTemplate:
case Decl::FunctionTemplate:
+ case Decl::TypeAliasTemplate:
case Decl::NamespaceAlias:
+ case Decl::Block:
break;
case Decl::CXXConstructor:
// Skip function templates
@@ -2216,6 +2241,23 @@ void CodeGenFunction::EmitDeclMetadata() {
}
}
+void CodeGenModule::EmitCoverageFile() {
+ if (!getCodeGenOpts().CoverageFile.empty()) {
+ if (llvm::NamedMDNode *CUNode = TheModule.getNamedMetadata("llvm.dbg.cu")) {
+ llvm::NamedMDNode *GCov = TheModule.getOrInsertNamedMetadata("llvm.gcov");
+ llvm::LLVMContext &Ctx = TheModule.getContext();
+ llvm::MDString *CoverageFile =
+ llvm::MDString::get(Ctx, getCodeGenOpts().CoverageFile);
+ for (int i = 0, e = CUNode->getNumOperands(); i != e; ++i) {
+ llvm::MDNode *CU = CUNode->getOperand(i);
+ llvm::Value *node[] = { CoverageFile, CU };
+ llvm::MDNode *N = llvm::MDNode::get(Ctx, node);
+ GCov->addOperand(N);
+ }
+ }
+ }
+}
+
///@name Custom Runtime Function Interfaces
///@{
//
@@ -2234,14 +2276,11 @@ llvm::Constant *CodeGenModule::getBlockObjectDispose() {
}
// Otherwise construct the function by hand.
- const llvm::FunctionType *FTy;
- std::vector<const llvm::Type*> ArgTys;
- const llvm::Type *ResultType = llvm::Type::getVoidTy(VMContext);
- ArgTys.push_back(Int8PtrTy);
- ArgTys.push_back(llvm::Type::getInt32Ty(VMContext));
- FTy = llvm::FunctionType::get(ResultType, ArgTys, false);
+ const llvm::Type *args[] = { Int8PtrTy, Int32Ty };
+ const llvm::FunctionType *fty
+ = llvm::FunctionType::get(VoidTy, args, false);
return BlockObjectDispose =
- CreateRuntimeFunction(FTy, "_Block_object_dispose");
+ CreateRuntimeFunction(fty, "_Block_object_dispose");
}
llvm::Constant *CodeGenModule::getBlockObjectAssign() {
@@ -2256,15 +2295,11 @@ llvm::Constant *CodeGenModule::getBlockObjectAssign() {
}
// Otherwise construct the function by hand.
- const llvm::FunctionType *FTy;
- std::vector<const llvm::Type*> ArgTys;
- const llvm::Type *ResultType = llvm::Type::getVoidTy(VMContext);
- ArgTys.push_back(Int8PtrTy);
- ArgTys.push_back(Int8PtrTy);
- ArgTys.push_back(llvm::Type::getInt32Ty(VMContext));
- FTy = llvm::FunctionType::get(ResultType, ArgTys, false);
+ const llvm::Type *args[] = { Int8PtrTy, Int8PtrTy, Int32Ty };
+ const llvm::FunctionType *fty
+ = llvm::FunctionType::get(VoidTy, args, false);
return BlockObjectAssign =
- CreateRuntimeFunction(FTy, "_Block_object_assign");
+ CreateRuntimeFunction(fty, "_Block_object_assign");
}
llvm::Constant *CodeGenModule::getNSConcreteGlobalBlock() {
diff --git a/lib/CodeGen/CodeGenModule.h b/lib/CodeGen/CodeGenModule.h
index 99c973c..779a352 100644
--- a/lib/CodeGen/CodeGenModule.h
+++ b/lib/CodeGen/CodeGenModule.h
@@ -97,16 +97,20 @@ namespace CodeGen {
};
struct CodeGenTypeCache {
+ /// void
+ const llvm::Type *VoidTy;
+
/// i8, i32, and i64
const llvm::IntegerType *Int8Ty, *Int32Ty, *Int64Ty;
/// int
const llvm::IntegerType *IntTy;
- /// intptr_t and size_t, which we assume are the same
+ /// intptr_t, size_t, and ptrdiff_t, which we assume are the same size.
union {
const llvm::IntegerType *IntPtrTy;
const llvm::IntegerType *SizeTy;
+ const llvm::IntegerType *PtrDiffTy;
};
/// void* in address space 0
@@ -735,6 +739,10 @@ private:
void EmitDeclMetadata();
+ /// EmitCoverageFile - Emit the llvm.gcov metadata used to tell LLVM where
+ /// to emit the .gcno and .gcda files in a way that persists in .bc files.
+ void EmitCoverageFile();
+
/// MayDeferGeneration - Determine if the given decl can be emitted
/// lazily; this is only relevant for definitions. The given decl
/// must be either a function or var decl.
diff --git a/lib/CodeGen/CodeGenTypes.h b/lib/CodeGen/CodeGenTypes.h
index dc383cb..ff1eb4c 100644
--- a/lib/CodeGen/CodeGenTypes.h
+++ b/lib/CodeGen/CodeGenTypes.h
@@ -220,8 +220,9 @@ public: // These are internal details of CGT that shouldn't be used externally.
/// GetExpandedTypes - Expand the type \arg Ty into the LLVM
/// 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,
- bool IsRecursive);
+ void GetExpandedTypes(QualType type,
+ llvm::SmallVectorImpl<const llvm::Type*> &expanded,
+ bool isRecursive);
/// IsZeroInitializable - Return whether a type can be
/// zero-initialized (in the C++ sense) with an LLVM zeroinitializer.
diff --git a/lib/CodeGen/ItaniumCXXABI.cpp b/lib/CodeGen/ItaniumCXXABI.cpp
index 33abf3a..12ef9bd 100644
--- a/lib/CodeGen/ItaniumCXXABI.cpp
+++ b/lib/CodeGen/ItaniumCXXABI.cpp
@@ -1007,11 +1007,9 @@ void ARMCXXABI::ReadArrayCookie(CodeGenFunction &CGF,
static llvm::Constant *getGuardAcquireFn(CodeGenModule &CGM,
const llvm::PointerType *GuardPtrTy) {
// int __cxa_guard_acquire(__guard *guard_object);
-
- std::vector<const llvm::Type*> Args(1, GuardPtrTy);
const llvm::FunctionType *FTy =
llvm::FunctionType::get(CGM.getTypes().ConvertType(CGM.getContext().IntTy),
- Args, /*isVarArg=*/false);
+ GuardPtrTy, /*isVarArg=*/false);
return CGM.CreateRuntimeFunction(FTy, "__cxa_guard_acquire");
}
@@ -1019,12 +1017,9 @@ static llvm::Constant *getGuardAcquireFn(CodeGenModule &CGM,
static llvm::Constant *getGuardReleaseFn(CodeGenModule &CGM,
const llvm::PointerType *GuardPtrTy) {
// void __cxa_guard_release(__guard *guard_object);
-
- std::vector<const llvm::Type*> Args(1, GuardPtrTy);
-
const llvm::FunctionType *FTy =
llvm::FunctionType::get(llvm::Type::getVoidTy(CGM.getLLVMContext()),
- Args, /*isVarArg=*/false);
+ GuardPtrTy, /*isVarArg=*/false);
return CGM.CreateRuntimeFunction(FTy, "__cxa_guard_release");
}
@@ -1032,12 +1027,9 @@ static llvm::Constant *getGuardReleaseFn(CodeGenModule &CGM,
static llvm::Constant *getGuardAbortFn(CodeGenModule &CGM,
const llvm::PointerType *GuardPtrTy) {
// void __cxa_guard_abort(__guard *guard_object);
-
- std::vector<const llvm::Type*> Args(1, GuardPtrTy);
-
const llvm::FunctionType *FTy =
llvm::FunctionType::get(llvm::Type::getVoidTy(CGM.getLLVMContext()),
- Args, /*isVarArg=*/false);
+ GuardPtrTy, /*isVarArg=*/false);
return CGM.CreateRuntimeFunction(FTy, "__cxa_guard_abort");
}
diff --git a/lib/CodeGen/ModuleBuilder.cpp b/lib/CodeGen/ModuleBuilder.cpp
index 8945028..4a2c4abbe 100644
--- a/lib/CodeGen/ModuleBuilder.cpp
+++ b/lib/CodeGen/ModuleBuilder.cpp
@@ -79,7 +79,7 @@ namespace {
MEnd = D->decls_end();
M != MEnd; ++M)
if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(*M))
- if (Method->isThisDeclarationADefinition() &&
+ if (Method->doesThisDeclarationHaveABody() &&
(Method->hasAttr<UsedAttr>() ||
Method->hasAttr<ConstructorAttr>()))
Builder->EmitTopLevelDecl(Method);
diff --git a/lib/CodeGen/TargetInfo.cpp b/lib/CodeGen/TargetInfo.cpp
index bc2472c..043ead7 100644
--- a/lib/CodeGen/TargetInfo.cpp
+++ b/lib/CodeGen/TargetInfo.cpp
@@ -648,7 +648,7 @@ ABIArgInfo X86_32ABIInfo::getIndirectResult(QualType Ty, bool ByVal) const {
unsigned TypeAlign = getContext().getTypeAlign(Ty) / 8;
unsigned StackAlign = getTypeStackAlignInBytes(Ty, TypeAlign);
if (StackAlign == 0)
- return ABIArgInfo::getIndirect(0);
+ return ABIArgInfo::getIndirect(4);
// If the stack alignment is less than the type alignment, realign the
// argument.
@@ -1315,13 +1315,10 @@ ABIArgInfo X86_64ABIInfo::getIndirectResult(QualType Ty) const {
if (isRecordWithNonTrivialDestructorOrCopyConstructor(Ty))
return ABIArgInfo::getIndirect(0, /*ByVal=*/false);
- // Compute the byval alignment. We trust the back-end to honor the
- // minimum ABI alignment for byval, to make cleaner IR.
- const unsigned MinABIAlign = 8;
- unsigned Align = getContext().getTypeAlign(Ty) / 8;
- if (Align > MinABIAlign)
- return ABIArgInfo::getIndirect(Align);
- return ABIArgInfo::getIndirect(0);
+ // Compute the byval alignment. We specify the alignment of the byval in all
+ // cases so that the mid-level optimizer knows the alignment of the byval.
+ unsigned Align = std::max(getContext().getTypeAlign(Ty) / 8, 8U);
+ return ABIArgInfo::getIndirect(Align);
}
/// Get16ByteVectorType - The ABI specifies that a value should be passed in an
@@ -2279,6 +2276,22 @@ public:
int getDwarfEHStackPointer(CodeGen::CodeGenModule &M) const {
return 13;
}
+
+ bool initDwarfEHRegSizeTable(CodeGen::CodeGenFunction &CGF,
+ llvm::Value *Address) const {
+ CodeGen::CGBuilderTy &Builder = CGF.Builder;
+ llvm::LLVMContext &Context = CGF.getLLVMContext();
+
+ const llvm::IntegerType *i8 = llvm::Type::getInt8Ty(Context);
+ llvm::Value *Four8 = llvm::ConstantInt::get(i8, 4);
+
+ // 0-15 are the 16 integer registers.
+ AssignToArrayRange(Builder, Address, Four8, 0, 15);
+
+ return false;
+ }
+
+
};
}
@@ -2845,10 +2858,21 @@ void MSP430TargetCodeGenInfo::SetTargetAttributes(const Decl *D,
//===----------------------------------------------------------------------===//
namespace {
+class MipsABIInfo : public ABIInfo {
+public:
+ MipsABIInfo(CodeGenTypes &CGT) : ABIInfo(CGT) {}
+
+ ABIArgInfo classifyReturnType(QualType RetTy) const;
+ ABIArgInfo classifyArgumentType(QualType RetTy) const;
+ virtual void computeInfo(CGFunctionInfo &FI) const;
+ virtual llvm::Value *EmitVAArg(llvm::Value *VAListAddr, QualType Ty,
+ CodeGenFunction &CGF) const;
+};
+
class MIPSTargetCodeGenInfo : public TargetCodeGenInfo {
public:
MIPSTargetCodeGenInfo(CodeGenTypes &CGT)
- : TargetCodeGenInfo(new DefaultABIInfo(CGT)) {}
+ : TargetCodeGenInfo(new MipsABIInfo(CGT)) {}
int getDwarfEHStackPointer(CodeGen::CodeGenModule &CGM) const {
return 29;
@@ -2859,6 +2883,54 @@ public:
};
}
+ABIArgInfo MipsABIInfo::classifyArgumentType(QualType Ty) const {
+ if (isAggregateTypeForABI(Ty)) {
+ // Ignore empty aggregates.
+ if (getContext().getTypeSize(Ty) == 0)
+ return ABIArgInfo::getIgnore();
+
+ return ABIArgInfo::getIndirect(0);
+ }
+
+ // Treat an enum type as its underlying type.
+ if (const EnumType *EnumTy = Ty->getAs<EnumType>())
+ Ty = EnumTy->getDecl()->getIntegerType();
+
+ return (Ty->isPromotableIntegerType() ?
+ ABIArgInfo::getExtend() : ABIArgInfo::getDirect());
+}
+
+ABIArgInfo MipsABIInfo::classifyReturnType(QualType RetTy) const {
+ if (RetTy->isVoidType())
+ return ABIArgInfo::getIgnore();
+
+ if (isAggregateTypeForABI(RetTy)) {
+ if (RetTy->isAnyComplexType())
+ return ABIArgInfo::getDirect();
+
+ return ABIArgInfo::getIndirect(0);
+ }
+
+ // Treat an enum type as its underlying type.
+ if (const EnumType *EnumTy = RetTy->getAs<EnumType>())
+ RetTy = EnumTy->getDecl()->getIntegerType();
+
+ return (RetTy->isPromotableIntegerType() ?
+ ABIArgInfo::getExtend() : ABIArgInfo::getDirect());
+}
+
+void MipsABIInfo::computeInfo(CGFunctionInfo &FI) const {
+ FI.getReturnInfo() = classifyReturnType(FI.getReturnType());
+ for (CGFunctionInfo::arg_iterator it = FI.arg_begin(), ie = FI.arg_end();
+ it != ie; ++it)
+ it->info = classifyArgumentType(it->type);
+}
+
+llvm::Value* MipsABIInfo::EmitVAArg(llvm::Value *VAListAddr, QualType Ty,
+ CodeGenFunction &CGF) const {
+ return 0;
+}
+
bool
MIPSTargetCodeGenInfo::initDwarfEHRegSizeTable(CodeGen::CodeGenFunction &CGF,
llvm::Value *Address) const {
diff --git a/lib/Driver/Driver.cpp b/lib/Driver/Driver.cpp
index fc4d86c..eb878a3 100644
--- a/lib/Driver/Driver.cpp
+++ b/lib/Driver/Driver.cpp
@@ -46,14 +46,14 @@
using namespace clang::driver;
using namespace clang;
-Driver::Driver(llvm::StringRef _ClangExecutable,
- llvm::StringRef _DefaultHostTriple,
- llvm::StringRef _DefaultImageName,
+Driver::Driver(llvm::StringRef ClangExecutable,
+ llvm::StringRef DefaultHostTriple,
+ llvm::StringRef DefaultImageName,
bool IsProduction, bool CXXIsProduction,
- Diagnostic &_Diags)
- : Opts(createDriverOptTable()), Diags(_Diags),
- ClangExecutable(_ClangExecutable), UseStdLib(true),
- DefaultHostTriple(_DefaultHostTriple), DefaultImageName(_DefaultImageName),
+ Diagnostic &Diags)
+ : Opts(createDriverOptTable()), Diags(Diags),
+ ClangExecutable(ClangExecutable), UseStdLib(true),
+ DefaultHostTriple(DefaultHostTriple), DefaultImageName(DefaultImageName),
DriverTitle("clang \"gcc-compatible\" driver"),
Host(0),
CCPrintOptionsFilename(0), CCPrintHeadersFilename(0),
@@ -398,9 +398,10 @@ void Driver::PrintVersion(const Compilation &C, llvm::raw_ostream &OS) const {
/// 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 = DiagnosticIDs::getCategoryNameFromID(i); ++i)
- OS << i << ',' << CategoryName << '\n';
+ // Skip the empty category.
+ for (unsigned i = 1, max = DiagnosticIDs::getNumberOfCategories();
+ i != max; ++i)
+ OS << i << ',' << DiagnosticIDs::getCategoryNameFromID(i) << '\n';
}
bool Driver::HandleImmediateArgs(const Compilation &C) {
@@ -569,14 +570,14 @@ void Driver::PrintActions(const Compilation &C) const {
PrintActions1(C, *it, Ids);
}
-/// \brief Check whether the given input tree contains any compilation (or
-/// assembly) actions.
-static bool ContainsCompileAction(const Action *A) {
+/// \brief Check whether the given input tree contains any compilation or
+/// assembly actions.
+static bool ContainsCompileOrAssembleAction(const Action *A) {
if (isa<CompileJobAction>(A) || isa<AssembleJobAction>(A))
return true;
for (Action::const_iterator it = A->begin(), ie = A->end(); it != ie; ++it)
- if (ContainsCompileAction(*it))
+ if (ContainsCompileOrAssembleAction(*it))
return true;
return false;
@@ -667,7 +668,7 @@ void Driver::BuildUniversalActions(const ToolChain &TC,
Arg *A = Args.getLastArg(options::OPT_g_Group);
if (A && !A->getOption().matches(options::OPT_g0) &&
!A->getOption().matches(options::OPT_gstabs) &&
- ContainsCompileAction(Actions.back())) {
+ ContainsCompileOrAssembleAction(Actions.back())) {
ActionList Inputs;
Inputs.push_back(Actions.back());
Actions.pop_back();
diff --git a/lib/Driver/HostInfo.cpp b/lib/Driver/HostInfo.cpp
index 198af54..3b1c2c7 100644
--- a/lib/Driver/HostInfo.cpp
+++ b/lib/Driver/HostInfo.cpp
@@ -414,15 +414,20 @@ ToolChain *NetBSDHostInfo::CreateToolChain(const ArgList &Args,
(A->getOption().matches(options::OPT_m32)) ? "powerpc" : "powerpc64";
}
}
+ llvm::Triple TargetTriple(getTriple());
+ TargetTriple.setArchName(ArchName);
- ToolChain *&TC = ToolChains[ArchName];
- if (!TC) {
- llvm::Triple TCTriple(getTriple());
- TCTriple.setArchName(ArchName);
+ ToolChain *TC;
- TC = new toolchains::NetBSD(*this, TCTriple);
+ // XXX Cache toolchain even if -m32 is used
+ if (Arch == ArchName) {
+ TC = ToolChains[ArchName];
+ if (TC)
+ return TC;
}
+ TC = new toolchains::NetBSD(*this, TargetTriple, getTriple());
+
return TC;
}
diff --git a/lib/Driver/ToolChains.cpp b/lib/Driver/ToolChains.cpp
index 4668d73..ca613e3 100644
--- a/lib/Driver/ToolChains.cpp
+++ b/lib/Driver/ToolChains.cpp
@@ -9,6 +9,10 @@
#include "ToolChains.h"
+#ifdef HAVE_CLANG_CONFIG_H
+# include "clang/Config/config.h"
+#endif
+
#include "clang/Driver/Arg.h"
#include "clang/Driver/ArgList.h"
#include "clang/Driver/Compilation.h"
@@ -115,7 +119,7 @@ llvm::StringRef Darwin::getDarwinArchName(const ArgList &Args) const {
switch (getTriple().getArch()) {
default:
return getArchName();
-
+
case llvm::Triple::thumb:
case llvm::Triple::arm: {
if (const Arg *A = Args.getLastArg(options::OPT_march_EQ))
@@ -145,10 +149,10 @@ std::string Darwin::ComputeEffectiveClangTriple(const ArgList &Args) const {
// the default triple).
if (!isTargetInitialized())
return Triple.getTriple();
-
+
unsigned Version[3];
getTargetVersion(Version);
-
+
llvm::SmallString<16> Str;
llvm::raw_svector_ostream(Str)
<< (isTargetIPhoneOS() ? "ios" : "macosx")
@@ -558,7 +562,7 @@ void DarwinClang::AddCCKextLibArgs(const ArgList &Args,
P.appendComponent("lib");
P.appendComponent("darwin");
P.appendComponent("libclang_rt.cc_kext.a");
-
+
// For now, allow missing resource libraries to support developers who may
// not have compiler-rt checked out or integrated into their build.
bool Exists;
@@ -624,7 +628,7 @@ DerivedArgList *Darwin::TranslateArgs(const DerivedArgList &Args,
DAL->AddSeparateArg(OriginalArg,
Opts.getOption(options::OPT_Zlinker_input),
A->getValue(Args, i));
-
+
}
continue;
}
@@ -915,8 +919,8 @@ TCEToolChain::~TCEToolChain() {
delete it->second;
}
-bool TCEToolChain::IsMathErrnoDefault() const {
- return true;
+bool TCEToolChain::IsMathErrnoDefault() const {
+ return true;
}
bool TCEToolChain::IsUnwindTablesDefault() const {
@@ -931,7 +935,7 @@ const char *TCEToolChain::GetForcedPicModel() const {
return 0;
}
-Tool &TCEToolChain::SelectTool(const Compilation &C,
+Tool &TCEToolChain::SelectTool(const Compilation &C,
const JobAction &JA,
const ActionList &Inputs) const {
Action::ActionClass Key;
@@ -1002,7 +1006,12 @@ FreeBSD::FreeBSD(const HostInfo &Host, const llvm::Triple& Triple)
llvm::Triple(getDriver().DefaultHostTriple).getArch() ==
llvm::Triple::x86_64)
Lib32 = true;
-
+
+ if (Triple.getArch() == llvm::Triple::ppc &&
+ llvm::Triple(getDriver().DefaultHostTriple).getArch() ==
+ llvm::Triple::ppc64)
+ Lib32 = true;
+
if (Lib32) {
getFilePaths().push_back("/usr/lib32");
} else {
@@ -1043,14 +1052,14 @@ Tool &FreeBSD::SelectTool(const Compilation &C, const JobAction &JA,
/// NetBSD - NetBSD tool chain which can call as(1) and ld(1) directly.
-NetBSD::NetBSD(const HostInfo &Host, const llvm::Triple& Triple)
- : Generic_ELF(Host, Triple) {
+NetBSD::NetBSD(const HostInfo &Host, const llvm::Triple& Triple,
+ const llvm::Triple& ToolTriple)
+ : Generic_ELF(Host, Triple), ToolTriple(ToolTriple) {
// Determine if we are compiling 32-bit code on an x86_64 platform.
bool Lib32 = false;
- if (Triple.getArch() == llvm::Triple::x86 &&
- llvm::Triple(getDriver().DefaultHostTriple).getArch() ==
- llvm::Triple::x86_64)
+ if (ToolTriple.getArch() == llvm::Triple::x86_64 &&
+ Triple.getArch() == llvm::Triple::x86)
Lib32 = true;
if (getDriver().UseStdLib) {
@@ -1080,10 +1089,11 @@ Tool &NetBSD::SelectTool(const Compilation &C, const JobAction &JA,
if (UseIntegratedAs)
T = new tools::ClangAs(*this);
else
- T = new tools::netbsd::Assemble(*this);
+ T = new tools::netbsd::Assemble(*this, ToolTriple);
break;
case Action::LinkJobClass:
- T = new tools::netbsd::Link(*this); break;
+ T = new tools::netbsd::Link(*this, ToolTriple);
+ break;
default:
T = &Generic_GCC::SelectTool(C, JA, Inputs);
}
@@ -1172,12 +1182,18 @@ enum LinuxDistro {
ArchLinux,
DebianLenny,
DebianSqueeze,
+ DebianWheezy,
Exherbo,
+ RHEL4,
+ RHEL5,
+ RHEL6,
Fedora13,
Fedora14,
Fedora15,
FedoraRawhide,
OpenSuse11_3,
+ OpenSuse11_4,
+ OpenSuse12_1,
UbuntuHardy,
UbuntuIntrepid,
UbuntuJaunty,
@@ -1185,27 +1201,31 @@ enum LinuxDistro {
UbuntuLucid,
UbuntuMaverick,
UbuntuNatty,
+ UbuntuOneiric,
UnknownDistro
};
-static bool IsFedora(enum LinuxDistro Distro) {
+static bool IsRedhat(enum LinuxDistro Distro) {
return Distro == Fedora13 || Distro == Fedora14 ||
- Distro == Fedora15 || Distro == FedoraRawhide;
+ Distro == Fedora15 || Distro == FedoraRawhide ||
+ Distro == RHEL4 || Distro == RHEL5 || Distro == RHEL6;
}
static bool IsOpenSuse(enum LinuxDistro Distro) {
- return Distro == OpenSuse11_3;
+ return Distro == OpenSuse11_3 || Distro == OpenSuse11_4 ||
+ Distro == OpenSuse12_1;
}
static bool IsDebian(enum LinuxDistro Distro) {
- return Distro == DebianLenny || Distro == DebianSqueeze;
+ return Distro == DebianLenny || Distro == DebianSqueeze ||
+ Distro == DebianWheezy;
}
static bool IsUbuntu(enum LinuxDistro Distro) {
return Distro == UbuntuHardy || Distro == UbuntuIntrepid ||
- Distro == UbuntuLucid || Distro == UbuntuMaverick ||
+ Distro == UbuntuLucid || Distro == UbuntuMaverick ||
Distro == UbuntuJaunty || Distro == UbuntuKarmic ||
- Distro == UbuntuNatty;
+ Distro == UbuntuNatty || Distro == UbuntuOneiric;
}
static bool IsDebianBased(enum LinuxDistro Distro) {
@@ -1223,7 +1243,8 @@ static bool HasMultilib(llvm::Triple::ArchType Arch, enum LinuxDistro Distro) {
}
if (Arch == llvm::Triple::ppc64)
return true;
- if ((Arch == llvm::Triple::x86 || Arch == llvm::Triple::ppc) && IsDebianBased(Distro))
+ if ((Arch == llvm::Triple::x86 || Arch == llvm::Triple::ppc) &&
+ IsDebianBased(Distro))
return true;
return false;
}
@@ -1249,6 +1270,8 @@ static LinuxDistro DetectLinuxDistro(llvm::Triple::ArchType Arch) {
return UbuntuMaverick;
else if (Lines[i] == "DISTRIB_CODENAME=natty")
return UbuntuNatty;
+ else if (Lines[i] == "DISTRIB_CODENAME=oneiric")
+ return UbuntuOneiric;
}
return UnknownDistro;
}
@@ -1264,6 +1287,17 @@ static LinuxDistro DetectLinuxDistro(llvm::Triple::ArchType Arch) {
else if (Data.startswith("Fedora release") &&
Data.find("Rawhide") != llvm::StringRef::npos)
return FedoraRawhide;
+ else if (Data.startswith("Red Hat Enterprise Linux") &&
+ Data.find("release 6") != llvm::StringRef::npos)
+ return RHEL6;
+ else if ((Data.startswith("Red Hat Enterprise Linux") ||
+ Data.startswith("CentOS")) &&
+ Data.find("release 5") != llvm::StringRef::npos)
+ return RHEL5;
+ else if ((Data.startswith("Red Hat Enterprise Linux") ||
+ Data.startswith("CentOS")) &&
+ Data.find("release 4") != llvm::StringRef::npos)
+ return RHEL4;
return UnknownDistro;
}
@@ -1273,6 +1307,8 @@ static LinuxDistro DetectLinuxDistro(llvm::Triple::ArchType Arch) {
return DebianLenny;
else if (Data.startswith("squeeze/sid"))
return DebianSqueeze;
+ else if (Data.startswith("wheezy/sid"))
+ return DebianWheezy;
return UnknownDistro;
}
@@ -1280,6 +1316,10 @@ static LinuxDistro DetectLinuxDistro(llvm::Triple::ArchType Arch) {
llvm::StringRef Data = File.get()->getBuffer();
if (Data.startswith("openSUSE 11.3"))
return OpenSuse11_3;
+ else if (Data.startswith("openSUSE 11.4"))
+ return OpenSuse11_4;
+ else if (Data.startswith("openSUSE 12.1"))
+ return OpenSuse12_1;
return UnknownDistro;
}
@@ -1293,6 +1333,54 @@ static LinuxDistro DetectLinuxDistro(llvm::Triple::ArchType Arch) {
return UnknownDistro;
}
+static std::string findGCCBaseLibDir(const std::string &GccTriple) {
+ // FIXME: Using CXX_INCLUDE_ROOT is here is a bit of a hack, but
+ // avoids adding yet another option to configure/cmake.
+ // It would probably be cleaner to break it in two variables
+ // CXX_GCC_ROOT with just /foo/bar
+ // CXX_GCC_VER with 4.5.2
+ // Then we would have
+ // CXX_INCLUDE_ROOT = CXX_GCC_ROOT/include/c++/CXX_GCC_VER
+ // and this function would return
+ // CXX_GCC_ROOT/lib/gcc/CXX_INCLUDE_ARCH/CXX_GCC_VER
+ llvm::SmallString<128> CxxIncludeRoot(CXX_INCLUDE_ROOT);
+ if (CxxIncludeRoot != "") {
+ // This is of the form /foo/bar/include/c++/4.5.2/
+ if (CxxIncludeRoot.back() == '/')
+ llvm::sys::path::remove_filename(CxxIncludeRoot); // remove the /
+ llvm::StringRef Version = llvm::sys::path::filename(CxxIncludeRoot);
+ llvm::sys::path::remove_filename(CxxIncludeRoot); // remove the version
+ llvm::sys::path::remove_filename(CxxIncludeRoot); // remove the c++
+ llvm::sys::path::remove_filename(CxxIncludeRoot); // remove the include
+ std::string ret(CxxIncludeRoot.c_str());
+ ret.append("/lib/gcc/");
+ ret.append(CXX_INCLUDE_ARCH);
+ ret.append("/");
+ ret.append(Version);
+ return ret;
+ }
+ static const char* GccVersions[] = {"4.6.0", "4.6",
+ "4.5.2", "4.5.1", "4.5",
+ "4.4.5", "4.4.4", "4.4.3", "4.4",
+ "4.3.4", "4.3.3", "4.3.2", "4.3",
+ "4.2.4", "4.2.3", "4.2.2", "4.2.1",
+ "4.2", "4.1.1"};
+ bool Exists;
+ for (unsigned i = 0; i < sizeof(GccVersions)/sizeof(char*); ++i) {
+ std::string Suffix = GccTriple + "/" + GccVersions[i];
+ std::string t1 = "/usr/lib/gcc/" + Suffix;
+ if (!llvm::sys::fs::exists(t1 + "/crtbegin.o", Exists) && Exists)
+ return t1;
+ std::string t2 = "/usr/lib64/gcc/" + Suffix;
+ if (!llvm::sys::fs::exists(t2 + "/crtbegin.o", Exists) && Exists)
+ return t2;
+ std::string t3 = "/usr/lib/" + GccTriple + "/gcc/" + Suffix;
+ if (!llvm::sys::fs::exists(t3 + "/crtbegin.o", Exists) && Exists)
+ return t3;
+ }
+ return "";
+}
+
Linux::Linux(const HostInfo &Host, const llvm::Triple &Triple)
: Generic_ELF(Host, Triple) {
llvm::Triple::ArchType Arch =
@@ -1366,42 +1454,23 @@ Linux::Linux(const HostInfo &Host, const llvm::Triple &Triple)
} else if (Arch == llvm::Triple::ppc) {
if (!llvm::sys::fs::exists("/usr/lib/powerpc-linux-gnu", Exists) && Exists)
GccTriple = "powerpc-linux-gnu";
- else if (!llvm::sys::fs::exists("/usr/lib/gcc/powerpc-unknown-linux-gnu", Exists) && Exists)
+ else if (!llvm::sys::fs::exists("/usr/lib/gcc/powerpc-unknown-linux-gnu",
+ Exists) && Exists)
GccTriple = "powerpc-unknown-linux-gnu";
} else if (Arch == llvm::Triple::ppc64) {
- if (!llvm::sys::fs::exists("/usr/lib/gcc/powerpc64-unknown-linux-gnu", Exists) && Exists)
+ if (!llvm::sys::fs::exists("/usr/lib/gcc/powerpc64-unknown-linux-gnu",
+ Exists) && Exists)
GccTriple = "powerpc64-unknown-linux-gnu";
- else if (!llvm::sys::fs::exists("/usr/lib64/gcc/powerpc64-unknown-linux-gnu", Exists) && Exists)
+ else if (!llvm::sys::fs::exists("/usr/lib64/gcc/"
+ "powerpc64-unknown-linux-gnu", Exists) &&
+ Exists)
GccTriple = "powerpc64-unknown-linux-gnu";
}
- const char* GccVersions[] = {"4.6.0",
- "4.5.2", "4.5.1", "4.5",
- "4.4.5", "4.4.4", "4.4.3", "4.4",
- "4.3.4", "4.3.3", "4.3.2", "4.3",
- "4.2.4", "4.2.3", "4.2.2", "4.2.1", "4.2"};
- std::string Base = "";
- for (unsigned i = 0; i < sizeof(GccVersions)/sizeof(char*); ++i) {
- std::string Suffix = GccTriple + "/" + GccVersions[i];
- std::string t1 = "/usr/lib/gcc/" + Suffix;
- if (!llvm::sys::fs::exists(t1 + "/crtbegin.o", Exists) && Exists) {
- Base = t1;
- break;
- }
- std::string t2 = "/usr/lib64/gcc/" + Suffix;
- if (!llvm::sys::fs::exists(t2 + "/crtbegin.o", Exists) && Exists) {
- Base = t2;
- break;
- }
- std::string t3 = "/usr/lib/" + GccTriple + "/gcc/" + Suffix;
- if (!llvm::sys::fs::exists(t3 + "/crtbegin.o", Exists) && Exists) {
- Base = t3;
- break;
- }
- }
-
+ std::string Base = findGCCBaseLibDir(GccTriple);
path_list &Paths = getFilePaths();
- bool Is32Bits = (getArch() == llvm::Triple::x86 || getArch() == llvm::Triple::ppc);
+ bool Is32Bits = (getArch() == llvm::Triple::x86 ||
+ getArch() == llvm::Triple::ppc);
std::string Suffix;
std::string Lib;
@@ -1422,7 +1491,7 @@ Linux::Linux(const HostInfo &Host, const llvm::Triple &Triple)
LinuxDistro Distro = DetectLinuxDistro(Arch);
- if (IsUbuntu(Distro)) {
+ if (IsOpenSuse(Distro) || IsUbuntu(Distro)) {
ExtraOpts.push_back("-z");
ExtraOpts.push_back("relro");
}
@@ -1430,21 +1499,28 @@ Linux::Linux(const HostInfo &Host, const llvm::Triple &Triple)
if (Arch == llvm::Triple::arm || Arch == llvm::Triple::thumb)
ExtraOpts.push_back("-X");
- if (IsFedora(Distro) || Distro == UbuntuMaverick || Distro == UbuntuNatty)
+ if (IsRedhat(Distro) || IsOpenSuse(Distro) || Distro == UbuntuMaverick ||
+ Distro == UbuntuNatty || Distro == UbuntuOneiric)
ExtraOpts.push_back("--hash-style=gnu");
- if (IsDebian(Distro) || Distro == UbuntuLucid || Distro == UbuntuJaunty ||
- Distro == UbuntuKarmic)
+ if (IsDebian(Distro) || IsOpenSuse(Distro) || Distro == UbuntuLucid ||
+ Distro == UbuntuJaunty || Distro == UbuntuKarmic)
ExtraOpts.push_back("--hash-style=both");
- if (IsFedora(Distro))
+ if (IsRedhat(Distro))
ExtraOpts.push_back("--no-add-needed");
- if (Distro == DebianSqueeze || IsOpenSuse(Distro) ||
- IsFedora(Distro) || Distro == UbuntuLucid || Distro == UbuntuMaverick ||
- Distro == UbuntuKarmic || Distro == UbuntuNatty)
+ if (Distro == DebianSqueeze || Distro == DebianWheezy ||
+ IsOpenSuse(Distro) ||
+ (IsRedhat(Distro) && Distro != RHEL4 && Distro != RHEL5) ||
+ Distro == UbuntuLucid ||
+ Distro == UbuntuMaverick || Distro == UbuntuKarmic ||
+ Distro == UbuntuNatty || Distro == UbuntuOneiric)
ExtraOpts.push_back("--build-id");
+ if (IsOpenSuse(Distro))
+ ExtraOpts.push_back("--enable-new-dtags");
+
if (Distro == ArchLinux)
Lib = "lib";
@@ -1453,9 +1529,14 @@ Linux::Linux(const HostInfo &Host, const llvm::Triple &Triple)
if (IsOpenSuse(Distro) && Is32Bits)
Paths.push_back(Base + "/../../../../" + GccTriple + "/lib/../lib");
Paths.push_back(Base + "/../../../../" + Lib);
- Paths.push_back("/lib/../" + Lib);
- Paths.push_back("/usr/lib/../" + Lib);
}
+
+ // FIXME: This is in here to find crt1.o. It is provided by libc, and
+ // libc (like gcc), can be installed in any directory. Once we are
+ // fetching this from a config file, we should have a libc prefix.
+ Paths.push_back("/lib/../" + Lib);
+ Paths.push_back("/usr/lib/../" + Lib);
+
if (!Suffix.empty())
Paths.push_back(Base);
if (IsOpenSuse(Distro))
diff --git a/lib/Driver/ToolChains.h b/lib/Driver/ToolChains.h
index 7a1a050..ace9b84 100644
--- a/lib/Driver/ToolChains.h
+++ b/lib/Driver/ToolChains.h
@@ -308,8 +308,11 @@ public:
};
class LLVM_LIBRARY_VISIBILITY NetBSD : public Generic_ELF {
+ const llvm::Triple ToolTriple;
+
public:
- NetBSD(const HostInfo &Host, const llvm::Triple& Triple);
+ NetBSD(const HostInfo &Host, const llvm::Triple& Triple,
+ const llvm::Triple& ToolTriple);
virtual Tool &SelectTool(const Compilation &C, const JobAction &JA,
const ActionList &Inputs) const;
diff --git a/lib/Driver/Tools.cpp b/lib/Driver/Tools.cpp
index 60803dd..8cd7adc 100644
--- a/lib/Driver/Tools.cpp
+++ b/lib/Driver/Tools.cpp
@@ -47,8 +47,9 @@ using namespace clang::driver::tools;
/// FindTargetProgramPath - Return path of the target specific version of
/// ProgName. If it doesn't exist, return path of ProgName itself.
static std::string FindTargetProgramPath(const ToolChain &TheToolChain,
+ const std::string TripleString,
const char *ProgName) {
- std::string Executable(TheToolChain.getTripleString() + "-" + ProgName);
+ std::string Executable(TripleString + "-" + ProgName);
std::string Path(TheToolChain.GetProgramPath(Executable.c_str()));
if (Path != Executable)
return Path;
@@ -146,6 +147,22 @@ static void AddLinkerInputs(const ToolChain &TC,
}
}
+static void addProfileRT(const ToolChain &TC, const ArgList &Args,
+ ArgStringList &CmdArgs) {
+ if (Args.hasArg(options::OPT_fprofile_arcs) ||
+ Args.hasArg(options::OPT_fprofile_generate) ||
+ Args.hasArg(options::OPT_fcreate_profile) ||
+ Args.hasArg(options::OPT_coverage)) {
+ // GCC links libgcov.a by adding -L<inst>/gcc/lib/gcc/<triple>/<ver> -lgcov
+ // to the link line. We cannot do the same thing because unlike gcov
+ // there is a libprofile_rt.so. We used to use the -l:libprofile_rt.a
+ // syntax, but that is not supported by old linkers.
+ const char *lib = Args.MakeArgString(TC.getDriver().Dir + "/../lib/" +
+ "libprofile_rt.a");
+ CmdArgs.push_back(lib);
+ }
+}
+
void Clang::AddPreprocessingOptions(const Driver &D,
const ArgList &Args,
ArgStringList &CmdArgs,
@@ -428,6 +445,7 @@ static bool isSignedCharDefault(const llvm::Triple &Triple) {
default:
return true;
+ case llvm::Triple::arm:
case llvm::Triple::ppc:
case llvm::Triple::ppc64:
if (Triple.getOS() == llvm::Triple::Darwin)
@@ -652,7 +670,7 @@ void Clang::AddMIPSTargetArgs(const ArgList &Args,
else if (MArch == "r6000")
CmdArgs.push_back("mips2");
else
- CmdArgs.push_back(MArch.str().c_str());
+ CmdArgs.push_back(Args.MakeArgString(MArch));
}
// Select the float ABI as determined by -msoft-float, -mhard-float, and
@@ -761,34 +779,34 @@ void Clang::AddX86TargetArgs(const ArgList &Args,
if (!CPUName) {
// FIXME: Need target hooks.
if (getToolChain().getOS().startswith("darwin")) {
- if (getToolChain().getArchName() == "x86_64")
+ if (getToolChain().getArch() == llvm::Triple::x86_64)
CPUName = "core2";
- else if (getToolChain().getArchName() == "i386")
+ else if (getToolChain().getArch() == llvm::Triple::x86)
CPUName = "yonah";
} else if (getToolChain().getOS().startswith("haiku")) {
- if (getToolChain().getArchName() == "x86_64")
+ if (getToolChain().getArch() == llvm::Triple::x86_64)
CPUName = "x86-64";
- else if (getToolChain().getArchName() == "i386")
+ else if (getToolChain().getArch() == llvm::Triple::x86)
CPUName = "i586";
} else if (getToolChain().getOS().startswith("openbsd")) {
- if (getToolChain().getArchName() == "x86_64")
+ if (getToolChain().getArch() == llvm::Triple::x86_64)
CPUName = "x86-64";
- else if (getToolChain().getArchName() == "i386")
+ else if (getToolChain().getArch() == llvm::Triple::x86)
CPUName = "i486";
} else if (getToolChain().getOS().startswith("freebsd")) {
- if (getToolChain().getArchName() == "x86_64")
+ if (getToolChain().getArch() == llvm::Triple::x86_64)
CPUName = "x86-64";
- else if (getToolChain().getArchName() == "i386")
+ else if (getToolChain().getArch() == llvm::Triple::x86)
CPUName = "i486";
} else if (getToolChain().getOS().startswith("netbsd")) {
- if (getToolChain().getArchName() == "x86_64")
+ if (getToolChain().getArch() == llvm::Triple::x86_64)
CPUName = "x86-64";
- else if (getToolChain().getArchName() == "i386")
+ else if (getToolChain().getArch() == llvm::Triple::x86)
CPUName = "i486";
} else {
- if (getToolChain().getArchName() == "x86_64")
+ if (getToolChain().getArch() == llvm::Triple::x86_64)
CPUName = "x86-64";
- else if (getToolChain().getArchName() == "i386")
+ else if (getToolChain().getArch() == llvm::Triple::x86)
CPUName = "pentium4";
}
}
@@ -907,21 +925,63 @@ static void addExceptionArgs(const ArgList &Args, types::ID InputType,
static bool ShouldDisableCFI(const ArgList &Args,
const ToolChain &TC) {
+ if (TC.getTriple().getOS() == llvm::Triple::Darwin) {
+ // The native darwin assembler doesn't support cfi directives, so
+ // we disable them if we think the .s file will be passed to it.
+
+ // FIXME: Duplicated code with ToolChains.cpp
+ // FIXME: This doesn't belong here, but ideally we will support static soon
+ // anyway.
+ bool HasStatic = (Args.hasArg(options::OPT_mkernel) ||
+ Args.hasArg(options::OPT_static) ||
+ Args.hasArg(options::OPT_fapple_kext));
+ bool IsIADefault = TC.IsIntegratedAssemblerDefault() && !HasStatic;
+ bool UseIntegratedAs = Args.hasFlag(options::OPT_integrated_as,
+ options::OPT_no_integrated_as,
+ IsIADefault);
+ bool UseCFI = Args.hasFlag(options::OPT_fdwarf2_cfi_asm,
+ options::OPT_fno_dwarf2_cfi_asm,
+ UseIntegratedAs);
+ return !UseCFI;
+ }
+
+ // For now we assume that every other assembler support CFI.
+ return false;
+}
+
+/// \brief Check whether the given input tree contains any compilation actions.
+static bool ContainsCompileAction(const Action *A) {
+ if (isa<CompileJobAction>(A))
+ return true;
+
+ for (Action::const_iterator it = A->begin(), ie = A->end(); it != ie; ++it)
+ if (ContainsCompileAction(*it))
+ return true;
- // FIXME: Duplicated code with ToolChains.cpp
- // FIXME: This doesn't belong here, but ideally we will support static soon
- // anyway.
- bool HasStatic = (Args.hasArg(options::OPT_mkernel) ||
- Args.hasArg(options::OPT_static) ||
- Args.hasArg(options::OPT_fapple_kext));
- bool IsIADefault = TC.IsIntegratedAssemblerDefault() && !HasStatic;
- bool UseIntegratedAs = Args.hasFlag(options::OPT_integrated_as,
- options::OPT_no_integrated_as,
- IsIADefault);
- bool UseCFI = Args.hasFlag(options::OPT_fdwarf2_cfi_asm,
- options::OPT_fno_dwarf2_cfi_asm,
- UseIntegratedAs);
- return !UseCFI;
+ return false;
+}
+
+/// \brief Check if -relax-all should be passed to the internal assembler.
+/// This is done by default when compiling non-assembler source with -O0.
+static bool UseRelaxAll(Compilation &C, const ArgList &Args) {
+ bool RelaxDefault = true;
+
+ if (Arg *A = Args.getLastArg(options::OPT_O_Group))
+ RelaxDefault = A->getOption().matches(options::OPT_O0);
+
+ if (RelaxDefault) {
+ RelaxDefault = false;
+ for (ActionList::const_iterator it = C.getActions().begin(),
+ ie = C.getActions().end(); it != ie; ++it) {
+ if (ContainsCompileAction(*it)) {
+ RelaxDefault = true;
+ break;
+ }
+ }
+ }
+
+ return Args.hasFlag(options::OPT_mrelax_all, options::OPT_mno_relax_all,
+ RelaxDefault);
}
void Clang::ConstructJob(Compilation &C, const JobAction &JA,
@@ -959,13 +1019,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
} 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))
+ if (UseRelaxAll(C, Args))
CmdArgs.push_back("-mrelax-all");
// When using an integrated assembler, translate -Wa, and -Xassembler
@@ -983,6 +1037,9 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
// Do nothing, this is the default and we don't support anything else.
} else if (Value == "-L") {
CmdArgs.push_back("-msave-temp-labels");
+ } else if (Value == "--fatal-warnings") {
+ CmdArgs.push_back("-mllvm");
+ CmdArgs.push_back("-fatal-assembler-warnings");
} else {
D.Diag(clang::diag::err_drv_unsupported_option_argument)
<< A->getOption().getName() << Value;
@@ -1303,6 +1360,14 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
Args.hasArg(options::OPT_coverage))
CmdArgs.push_back("-femit-coverage-data");
+ if (C.getArgs().hasArg(options::OPT_c) ||
+ C.getArgs().hasArg(options::OPT_S)) {
+ if (Output.isFilename()) {
+ CmdArgs.push_back("-coverage-file");
+ CmdArgs.push_back(Args.MakeArgString(Output.getFilename()));
+ }
+ }
+
Args.AddLastArg(CmdArgs, options::OPT_nostdinc);
Args.AddLastArg(CmdArgs, options::OPT_nostdincxx);
Args.AddLastArg(CmdArgs, options::OPT_nobuiltininc);
@@ -1477,6 +1542,12 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
options::OPT_fno_lax_vector_conversions))
CmdArgs.push_back("-fno-lax-vector-conversions");
+ // -fobjc-infer-related-result-type is the default.
+ if (Args.hasFlag(options::OPT_fobjc_infer_related_result_type,
+ options::OPT_fno_objc_infer_related_result_type,
+ /*Default=*/true))
+ CmdArgs.push_back("-fobjc-infer-related-result-type");
+
// Handle -fobjc-gc and -fobjc-gc-only. They are exclusive, and -fobjc-gc-only
// takes precedence.
const Arg *GCArg = Args.getLastArg(options::OPT_fobjc_gc_only);
@@ -1495,7 +1566,6 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
if (Args.getLastArg(options::OPT_fapple_kext))
CmdArgs.push_back("-fapple-kext");
- Args.AddLastArg(CmdArgs, options::OPT_fno_show_column);
Args.AddLastArg(CmdArgs, options::OPT_fobjc_sender_dependent_dispatch);
Args.AddLastArg(CmdArgs, options::OPT_fdiagnostics_print_source_range_info);
Args.AddLastArg(CmdArgs, options::OPT_fdiagnostics_parseable_fixits);
@@ -1546,6 +1616,12 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
CmdArgs.push_back(Args.MakeArgString(llvm::Twine(StackProtectorLevel)));
}
+ // Translate -mstackrealign
+ if (Args.hasArg(options::OPT_mstackrealign)) {
+ CmdArgs.push_back("-backend-option");
+ CmdArgs.push_back("-force-align-stack");
+ }
+
// Forward -f options with positive and negative forms; we translate
// these by hand.
@@ -1653,6 +1729,11 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
options::OPT_fno_gnu_keywords))
A->render(Args, CmdArgs);
+ if (Args.hasFlag(options::OPT_fgnu89_inline,
+ options::OPT_fno_gnu89_inline,
+ false))
+ CmdArgs.push_back("-fgnu89-inline");
+
// -fnext-runtime defaults to on Darwin and when rewriting Objective-C, and is
// -the -cc1 default.
bool NeXTRuntimeIsDefault =
@@ -1815,6 +1896,12 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
CmdArgs.push_back(A->getValue(Args));
}
+ if (const Arg *A =
+ Args.getLastArg(options::OPT_fdiagnostics_format_EQ)) {
+ CmdArgs.push_back("-fdiagnostics-format");
+ CmdArgs.push_back(A->getValue(Args));
+ }
+
if (Arg *A = Args.getLastArg(
options::OPT_fdiagnostics_show_note_include_stack,
options::OPT_fno_diagnostics_show_note_include_stack)) {
@@ -1836,6 +1923,11 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
options::OPT_fno_show_source_location))
CmdArgs.push_back("-fno-show-source-location");
+ if (!Args.hasFlag(options::OPT_fshow_column,
+ options::OPT_fno_show_column,
+ true))
+ CmdArgs.push_back("-fno-show-column");
+
if (!Args.hasFlag(options::OPT_fspell_checking,
options::OPT_fno_spell_checking))
CmdArgs.push_back("-fno-spell-checking");
@@ -2005,13 +2097,7 @@ void ClangAs::ConstructJob(Compilation &C, const JobAction &JA,
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))
+ if (UseRelaxAll(C, Args))
CmdArgs.push_back("-relax-all");
// Ignore explicit -force_cpusubtype_ALL option.
@@ -2893,12 +2979,17 @@ void darwin::Link::AddLinkArgs(Compilation &C,
Args.AddAllArgs(CmdArgs, options::OPT_sub__library);
Args.AddAllArgs(CmdArgs, options::OPT_sub__umbrella);
- Args.AddAllArgsTranslated(CmdArgs, options::OPT_isysroot, "-syslibroot");
- if (getDarwinToolChain().isTargetIPhoneOS()) {
- if (!Args.hasArg(options::OPT_isysroot)) {
- CmdArgs.push_back("-syslibroot");
- CmdArgs.push_back("/Developer/SDKs/Extra");
- }
+ // Give --sysroot= preference, over the Apple specific behavior to also use
+ // --isysroot as the syslibroot.
+ if (const Arg *A = Args.getLastArg(options::OPT__sysroot_EQ)) {
+ CmdArgs.push_back("-syslibroot");
+ CmdArgs.push_back(A->getValue(Args));
+ } else if (const Arg *A = Args.getLastArg(options::OPT_isysroot)) {
+ CmdArgs.push_back("-syslibroot");
+ CmdArgs.push_back(A->getValue(Args));
+ } else if (getDarwinToolChain().isTargetIPhoneOS()) {
+ CmdArgs.push_back("-syslibroot");
+ CmdArgs.push_back("/Developer/SDKs/Extra");
}
Args.AddLastArg(CmdArgs, options::OPT_twolevel__namespace);
@@ -3059,12 +3150,6 @@ void darwin::Link::ConstructJob(Compilation &C, const JobAction &JA,
CmdArgs.push_back(LinkingOutput);
}
- if (Args.hasArg(options::OPT_fprofile_arcs) ||
- Args.hasArg(options::OPT_fprofile_generate) ||
- Args.hasArg(options::OPT_fcreate_profile) ||
- Args.hasArg(options::OPT_coverage))
- CmdArgs.push_back("-lgcov");
-
if (Args.hasArg(options::OPT_fnested_functions))
CmdArgs.push_back("-allow_stack_execute");
@@ -3085,6 +3170,8 @@ void darwin::Link::ConstructJob(Compilation &C, const JobAction &JA,
// endfile_spec is empty.
}
+ addProfileRT(getToolChain(), Args, CmdArgs);
+
Args.AddAllArgs(CmdArgs, options::OPT_T_Group);
Args.AddAllArgs(CmdArgs, options::OPT_F);
@@ -3124,14 +3211,14 @@ void darwin::Dsymutil::ConstructJob(Compilation &C, const JobAction &JA,
const char *LinkingOutput) const {
ArgStringList CmdArgs;
+ CmdArgs.push_back("-o");
+ CmdArgs.push_back(Output.getFilename());
+
assert(Inputs.size() == 1 && "Unable to handle multiple inputs.");
const InputInfo &Input = Inputs[0];
assert(Input.isFilename() && "Unexpected dsymutil input.");
CmdArgs.push_back(Input.getFilename());
- CmdArgs.push_back("-o");
- CmdArgs.push_back(Output.getFilename());
-
const char *Exec =
Args.MakeArgString(getToolChain().GetProgramPath("dsymutil"));
C.addCommand(new Command(JA, *this, Exec, CmdArgs));
@@ -3242,6 +3329,8 @@ void auroraux::Link::ConstructJob(Compilation &C, const JobAction &JA,
getToolChain().GetFilePath("crtend.o")));
}
+ addProfileRT(getToolChain(), Args, CmdArgs);
+
const char *Exec =
Args.MakeArgString(getToolChain().GetProgramPath("ld"));
C.addCommand(new Command(JA, *this, Exec, CmdArgs));
@@ -3377,6 +3466,8 @@ void freebsd::Assemble::ConstructJob(Compilation &C, const JobAction &JA,
if (getToolChain().getArchName() == "i386")
CmdArgs.push_back("--32");
+ if (getToolChain().getArchName() == "powerpc")
+ CmdArgs.push_back("-a32");
// Set byte order explicitly
if (getToolChain().getArchName() == "mips")
@@ -3433,6 +3524,11 @@ void freebsd::Link::ConstructJob(Compilation &C, const JobAction &JA,
CmdArgs.push_back("elf_i386_fbsd");
}
+ if (getToolChain().getArchName() == "powerpc") {
+ CmdArgs.push_back("-m");
+ CmdArgs.push_back("elf32ppc");
+ }
+
if (Output.isFilename()) {
CmdArgs.push_back("-o");
CmdArgs.push_back(Output.getFilename());
@@ -3541,6 +3637,8 @@ void freebsd::Link::ConstructJob(Compilation &C, const JobAction &JA,
"crtn.o")));
}
+ addProfileRT(getToolChain(), Args, CmdArgs);
+
const char *Exec =
Args.MakeArgString(getToolChain().GetProgramPath("ld"));
C.addCommand(new Command(JA, *this, Exec, CmdArgs));
@@ -3555,7 +3653,8 @@ void netbsd::Assemble::ConstructJob(Compilation &C, const JobAction &JA,
// When building 32-bit code on NetBSD/amd64, we have to explicitly
// instruct as in the base system to assemble 32-bit code.
- if (getToolChain().getArchName() == "i386")
+ if (ToolTriple.getArch() == llvm::Triple::x86_64 &&
+ getToolChain().getArch() == llvm::Triple::x86)
CmdArgs.push_back("--32");
@@ -3578,7 +3677,8 @@ void netbsd::Assemble::ConstructJob(Compilation &C, const JobAction &JA,
}
const char *Exec = Args.MakeArgString(FindTargetProgramPath(getToolChain(),
- "as"));
+ ToolTriple.getTriple(),
+ "as"));
C.addCommand(new Command(JA, *this, Exec, CmdArgs));
}
@@ -3609,7 +3709,8 @@ void netbsd::Link::ConstructJob(Compilation &C, const JobAction &JA,
// When building 32-bit code on NetBSD/amd64, we have to explicitly
// instruct ld in the base system to link 32-bit code.
- if (getToolChain().getArchName() == "i386") {
+ if (ToolTriple.getArch() == llvm::Triple::x86_64 &&
+ getToolChain().getArch() == llvm::Triple::x86) {
CmdArgs.push_back("-m");
CmdArgs.push_back("elf_i386");
}
@@ -3656,7 +3757,6 @@ void netbsd::Link::ConstructJob(Compilation &C, const JobAction &JA,
}
// FIXME: For some reason GCC passes -lgcc and -lgcc_s before adding
// the default system libraries. Just mimic this for now.
- CmdArgs.push_back("-lgcc");
if (Args.hasArg(options::OPT_static)) {
CmdArgs.push_back("-lgcc_eh");
} else {
@@ -3664,6 +3764,7 @@ void netbsd::Link::ConstructJob(Compilation &C, const JobAction &JA,
CmdArgs.push_back("-lgcc_s");
CmdArgs.push_back("--no-as-needed");
}
+ CmdArgs.push_back("-lgcc");
if (Args.hasArg(options::OPT_pthread))
CmdArgs.push_back("-lpthread");
@@ -3691,8 +3792,11 @@ void netbsd::Link::ConstructJob(Compilation &C, const JobAction &JA,
"crtn.o")));
}
+ addProfileRT(getToolChain(), Args, CmdArgs);
+
const char *Exec = Args.MakeArgString(FindTargetProgramPath(getToolChain(),
- "ld"));
+ ToolTriple.getTriple(),
+ "ld"));
C.addCommand(new Command(JA, *this, Exec, CmdArgs));
}
@@ -3854,10 +3958,10 @@ void linuxtools::Link::ConstructJob(Compilation &C, const JobAction &JA,
CmdArgs.push_back("-lm");
}
- if (Args.hasArg(options::OPT_static))
- CmdArgs.push_back("--start-group");
-
if (!Args.hasArg(options::OPT_nostdlib)) {
+ if (Args.hasArg(options::OPT_static))
+ CmdArgs.push_back("--start-group");
+
if (!D.CCCIsCXX)
CmdArgs.push_back("-lgcc");
@@ -3912,6 +4016,8 @@ void linuxtools::Link::ConstructJob(Compilation &C, const JobAction &JA,
}
}
+ addProfileRT(getToolChain(), Args, CmdArgs);
+
if (Args.hasArg(options::OPT_use_gold_plugin)) {
CmdArgs.push_back("-plugin");
std::string Plugin = ToolChain.getDriver().Dir + "/../lib/LLVMgold.so";
@@ -3994,6 +4100,8 @@ void minix::Link::ConstructJob(Compilation &C, const JobAction &JA,
"/usr/gnu/lib/libend.a")));
}
+ addProfileRT(getToolChain(), Args, CmdArgs);
+
const char *Exec =
Args.MakeArgString(getToolChain().GetProgramPath("/usr/gnu/bin/gld"));
C.addCommand(new Command(JA, *this, Exec, CmdArgs));
@@ -4149,6 +4257,8 @@ void dragonfly::Link::ConstructJob(Compilation &C, const JobAction &JA,
getToolChain().GetFilePath("crtn.o")));
}
+ addProfileRT(getToolChain(), Args, CmdArgs);
+
const char *Exec =
Args.MakeArgString(getToolChain().GetProgramPath("ld"));
C.addCommand(new Command(JA, *this, Exec, CmdArgs));
diff --git a/lib/Driver/Tools.h b/lib/Driver/Tools.h
index 93abf75..4a5a7e4 100644
--- a/lib/Driver/Tools.h
+++ b/lib/Driver/Tools.h
@@ -14,6 +14,7 @@
#include "clang/Driver/Types.h"
#include "clang/Driver/Util.h"
+#include "llvm/ADT/Triple.h"
#include "llvm/Support/Compiler.h"
namespace clang {
@@ -338,9 +339,12 @@ namespace freebsd {
/// netbsd -- Directly call GNU Binutils assembler and linker
namespace netbsd {
class LLVM_LIBRARY_VISIBILITY Assemble : public Tool {
+ private:
+ const llvm::Triple ToolTriple;
+
public:
- Assemble(const ToolChain &TC) : Tool("netbsd::Assemble", "assembler",
- TC) {}
+ Assemble(const ToolChain &TC, const llvm::Triple &ToolTriple)
+ : Tool("netbsd::Assemble", "assembler", TC), ToolTriple(ToolTriple) {}
virtual bool hasIntegratedCPP() const { return false; }
@@ -351,8 +355,12 @@ namespace netbsd {
const char *LinkingOutput) const;
};
class LLVM_LIBRARY_VISIBILITY Link : public Tool {
+ private:
+ const llvm::Triple ToolTriple;
+
public:
- Link(const ToolChain &TC) : Tool("netbsd::Link", "linker", TC) {}
+ Link(const ToolChain &TC, const llvm::Triple &ToolTriple)
+ : Tool("netbsd::Ling", "linker", TC), ToolTriple(ToolTriple) {}
virtual bool hasIntegratedCPP() const { return false; }
diff --git a/lib/Frontend/ASTConsumers.cpp b/lib/Frontend/ASTConsumers.cpp
index ecd6ef4..28d312a 100644
--- a/lib/Frontend/ASTConsumers.cpp
+++ b/lib/Frontend/ASTConsumers.cpp
@@ -173,7 +173,7 @@ void DeclContextPrinter::PrintDeclContext(const DeclContext* DC,
break;
case Decl::Function: {
const FunctionDecl* FD = cast<FunctionDecl>(DC);
- if (FD->isThisDeclarationADefinition())
+ if (FD->doesThisDeclarationHaveABody())
Out << "[function] ";
else
Out << "<function> ";
diff --git a/lib/Frontend/ASTUnit.cpp b/lib/Frontend/ASTUnit.cpp
index 2a12448..8827116 100644
--- a/lib/Frontend/ASTUnit.cpp
+++ b/lib/Frontend/ASTUnit.cpp
@@ -102,6 +102,7 @@ ASTUnit::ASTUnit(bool _MainFileIsAST)
ConcurrencyCheckValue(CheckUnlocked),
PreambleRebuildCounter(0), SavedMainFileBuffer(0), PreambleBuffer(0),
ShouldCacheCodeCompletionResults(false),
+ NestedMacroInstantiations(true),
CompletionCacheTopLevelHashValue(0),
PreambleTopLevelHashValue(0),
CurrentTopLevelHashValue(0),
@@ -579,6 +580,11 @@ ASTUnit *ASTUnit::LoadFromASTFile(const std::string &Filename,
Reader.reset(new ASTReader(AST->getSourceManager(), AST->getFileManager(),
AST->getDiagnostics()));
+
+ // Recover resources if we crash before exiting this method.
+ llvm::CrashRecoveryContextCleanupRegistrar<ASTReader>
+ ReaderCleanup(Reader.get());
+
Reader->setListener(new ASTInfoCollector(LangInfo, HeaderInfo, TargetTriple,
Predefines, Counter));
@@ -633,6 +639,11 @@ ASTUnit *ASTUnit::LoadFromASTFile(const std::string &Filename,
// AST file as needed.
ASTReader *ReaderPtr = Reader.get();
llvm::OwningPtr<ExternalASTSource> Source(Reader.take());
+
+ // Unregister the cleanup for ASTReader. It will get cleaned up
+ // by the ASTUnit cleanup.
+ ReaderCleanup.unregister();
+
Context.setExternalSource(Source);
// Create an AST consumer, even though it isn't used.
@@ -917,6 +928,8 @@ bool ASTUnit::Parse(llvm::MemoryBuffer *OverrideMainBuffer) {
// If the main file has been overridden due to the use of a preamble,
// make that override happen and introduce the preamble.
PreprocessorOptions &PreprocessorOpts = Clang->getPreprocessorOpts();
+ PreprocessorOpts.DetailedRecordIncludesNestedMacroInstantiations
+ = NestedMacroInstantiations;
std::string PriorImplicitPCHInclude;
if (OverrideMainBuffer) {
PreprocessorOpts.addRemappedFile(OriginalSourceFile, OverrideMainBuffer);
@@ -1554,6 +1567,119 @@ ASTUnit *ASTUnit::create(CompilerInvocation *CI,
return AST.take();
}
+ASTUnit *ASTUnit::LoadFromCompilerInvocationAction(CompilerInvocation *CI,
+ llvm::IntrusiveRefCntPtr<Diagnostic> Diags,
+ ASTFrontendAction *Action) {
+ assert(CI && "A CompilerInvocation is required");
+
+ // Create the AST unit.
+ llvm::OwningPtr<ASTUnit> AST;
+ AST.reset(new ASTUnit(false));
+ ConfigureDiags(Diags, 0, 0, *AST, /*CaptureDiagnostics*/false);
+ AST->Diagnostics = Diags;
+ AST->OnlyLocalDecls = false;
+ AST->CaptureDiagnostics = false;
+ AST->CompleteTranslationUnit = Action ? Action->usesCompleteTranslationUnit()
+ : true;
+ AST->ShouldCacheCodeCompletionResults = false;
+ AST->Invocation = CI;
+
+ // Recover resources if we crash before exiting this method.
+ llvm::CrashRecoveryContextCleanupRegistrar<ASTUnit>
+ ASTUnitCleanup(AST.get());
+ llvm::CrashRecoveryContextCleanupRegistrar<Diagnostic,
+ llvm::CrashRecoveryContextReleaseRefCleanup<Diagnostic> >
+ DiagCleanup(Diags.getPtr());
+
+ // We'll manage file buffers ourselves.
+ CI->getPreprocessorOpts().RetainRemappedFileBuffers = true;
+ CI->getFrontendOpts().DisableFree = false;
+ ProcessWarningOptions(AST->getDiagnostics(), CI->getDiagnosticOpts());
+
+ // Save the target features.
+ AST->TargetFeatures = CI->getTargetOpts().Features;
+
+ // Create the compiler instance to use for building the AST.
+ llvm::OwningPtr<CompilerInstance> Clang(new CompilerInstance());
+
+ // Recover resources if we crash before exiting this method.
+ llvm::CrashRecoveryContextCleanupRegistrar<CompilerInstance>
+ CICleanup(Clang.get());
+
+ Clang->setInvocation(CI);
+ AST->OriginalSourceFile = Clang->getFrontendOpts().Inputs[0].second;
+
+ // Set up diagnostics, capturing any diagnostics that would
+ // otherwise be dropped.
+ Clang->setDiagnostics(&AST->getDiagnostics());
+
+ // Create the target instance.
+ Clang->getTargetOpts().Features = AST->TargetFeatures;
+ Clang->setTarget(TargetInfo::CreateTargetInfo(Clang->getDiagnostics(),
+ Clang->getTargetOpts()));
+ if (!Clang->hasTarget())
+ return 0;
+
+ // Inform the target of the language options.
+ //
+ // FIXME: We shouldn't need to do this, the target should be immutable once
+ // created. This complexity should be lifted elsewhere.
+ Clang->getTarget().setForcedLangOptions(Clang->getLangOpts());
+
+ assert(Clang->getFrontendOpts().Inputs.size() == 1 &&
+ "Invocation must have exactly one source file!");
+ assert(Clang->getFrontendOpts().Inputs[0].first != IK_AST &&
+ "FIXME: AST inputs not yet supported here!");
+ assert(Clang->getFrontendOpts().Inputs[0].first != IK_LLVM_IR &&
+ "IR inputs not supported here!");
+
+ // Configure the various subsystems.
+ AST->FileSystemOpts = Clang->getFileSystemOpts();
+ AST->FileMgr = new FileManager(AST->FileSystemOpts);
+ AST->SourceMgr = new SourceManager(AST->getDiagnostics(), *AST->FileMgr);
+ AST->TheSema.reset();
+ AST->Ctx = 0;
+ AST->PP = 0;
+
+ // Create a file manager object to provide access to and cache the filesystem.
+ Clang->setFileManager(&AST->getFileManager());
+
+ // Create the source manager.
+ Clang->setSourceManager(&AST->getSourceManager());
+
+ ASTFrontendAction *Act = Action;
+
+ llvm::OwningPtr<TopLevelDeclTrackerAction> TrackerAct;
+ if (!Act) {
+ TrackerAct.reset(new TopLevelDeclTrackerAction(*AST));
+ Act = TrackerAct.get();
+ }
+
+ // Recover resources if we crash before exiting this method.
+ llvm::CrashRecoveryContextCleanupRegistrar<TopLevelDeclTrackerAction>
+ ActCleanup(TrackerAct.get());
+
+ if (!Act->BeginSourceFile(*Clang.get(),
+ Clang->getFrontendOpts().Inputs[0].second,
+ Clang->getFrontendOpts().Inputs[0].first))
+ return 0;
+
+ Act->Execute();
+
+ // Steal the created target, context, and preprocessor.
+ AST->TheSema.reset(Clang->takeSema());
+ AST->Consumer.reset(Clang->takeASTConsumer());
+ AST->Ctx = &Clang->getASTContext();
+ AST->PP = &Clang->getPreprocessor();
+ Clang->setSourceManager(0);
+ Clang->setFileManager(0);
+ AST->Target = &Clang->getTarget();
+
+ Act->EndSourceFile();
+
+ return AST.take();
+}
+
bool ASTUnit::LoadFromCompilerInvocation(bool PrecompilePreamble) {
if (!Invocation)
return true;
@@ -1589,7 +1715,8 @@ ASTUnit *ASTUnit::LoadFromCompilerInvocation(CompilerInvocation *CI,
bool CaptureDiagnostics,
bool PrecompilePreamble,
bool CompleteTranslationUnit,
- bool CacheCodeCompletionResults) {
+ bool CacheCodeCompletionResults,
+ bool NestedMacroInstantiations) {
// Create the AST unit.
llvm::OwningPtr<ASTUnit> AST;
AST.reset(new ASTUnit(false));
@@ -1600,6 +1727,7 @@ ASTUnit *ASTUnit::LoadFromCompilerInvocation(CompilerInvocation *CI,
AST->CompleteTranslationUnit = CompleteTranslationUnit;
AST->ShouldCacheCodeCompletionResults = CacheCodeCompletionResults;
AST->Invocation = CI;
+ AST->NestedMacroInstantiations = NestedMacroInstantiations;
// Recover resources if we crash before exiting this method.
llvm::CrashRecoveryContextCleanupRegistrar<ASTUnit>
@@ -1624,7 +1752,8 @@ ASTUnit *ASTUnit::LoadFromCommandLine(const char **ArgBegin,
bool CompleteTranslationUnit,
bool CacheCodeCompletionResults,
bool CXXPrecompilePreamble,
- bool CXXChainedPCH) {
+ bool CXXChainedPCH,
+ bool NestedMacroInstantiations) {
if (!Diags.getPtr()) {
// No diagnostics engine was provided, so create our own diagnostics object
// with the default options.
@@ -1691,6 +1820,7 @@ ASTUnit *ASTUnit::LoadFromCommandLine(const char **ArgBegin,
AST->NumStoredDiagnosticsInPreamble = StoredDiagnostics.size();
AST->StoredDiagnostics.swap(StoredDiagnostics);
AST->Invocation = CI;
+ AST->NestedMacroInstantiations = NestedMacroInstantiations;
// Recover resources if we crash before exiting this method.
llvm::CrashRecoveryContextCleanupRegistrar<ASTUnit>
@@ -2142,6 +2272,9 @@ void ASTUnit::CodeComplete(llvm::StringRef File, unsigned Line, unsigned Column,
PreprocessorOpts.PrecompiledPreambleBytes.second = false;
}
+ // Disable the preprocessing record
+ PreprocessorOpts.DetailedRecord = false;
+
llvm::OwningPtr<SyntaxOnlyAction> Act;
Act.reset(new SyntaxOnlyAction);
if (Act->BeginSourceFile(*Clang.get(), Clang->getFrontendOpts().Inputs[0].second,
diff --git a/lib/Frontend/CMakeLists.txt b/lib/Frontend/CMakeLists.txt
index 9d49e90..7dcbebf 100644
--- a/lib/Frontend/CMakeLists.txt
+++ b/lib/Frontend/CMakeLists.txt
@@ -18,7 +18,6 @@ add_clang_library(clangFrontend
CompilerInvocation.cpp
CreateInvocationFromCommandLine.cpp
DependencyFile.cpp
- DiagChecker.cpp
FrontendAction.cpp
FrontendActions.cpp
FrontendOptions.cpp
diff --git a/lib/Frontend/CompilerInstance.cpp b/lib/Frontend/CompilerInstance.cpp
index ace3c5a..38fcfe3 100644
--- a/lib/Frontend/CompilerInstance.cpp
+++ b/lib/Frontend/CompilerInstance.cpp
@@ -227,7 +227,8 @@ CompilerInstance::createPreprocessor(Diagnostic &Diags,
}
if (PPOpts.DetailedRecord)
- PP->createPreprocessingRecord();
+ PP->createPreprocessingRecord(
+ PPOpts.DetailedRecordIncludesNestedMacroInstantiations);
InitializePreprocessor(*PP, PPOpts, HSOpts, FEOpts);
diff --git a/lib/Frontend/CompilerInvocation.cpp b/lib/Frontend/CompilerInvocation.cpp
index 1d4cd15..536512a 100644
--- a/lib/Frontend/CompilerInvocation.cpp
+++ b/lib/Frontend/CompilerInvocation.cpp
@@ -277,6 +277,14 @@ static void DiagnosticOptsToArgs(const DiagnosticOptions &Opts,
Res.push_back("-fdiagnostics-show-category=id");
else if (Opts.ShowCategories == 2)
Res.push_back("-fdiagnostics-show-category=name");
+ switch (Opts.Format) {
+ case DiagnosticOptions::Clang:
+ Res.push_back("-fdiagnostics-format=clang"); break;
+ case DiagnosticOptions::Msvc:
+ Res.push_back("-fdiagnostics-format=msvc"); break;
+ case DiagnosticOptions::Vi:
+ Res.push_back("-fdiagnostics-format=vi"); break;
+ }
if (Opts.ErrorLimit) {
Res.push_back("-ferror-limit");
Res.push_back(llvm::utostr(Opts.ErrorLimit));
@@ -662,6 +670,9 @@ static void LangOptsToArgs(const LangOptions &Opts,
Res.push_back("-fobjc-gc-only");
}
}
+ if (Opts.ObjCInferRelatedResultType)
+ Res.push_back("-fobjc-infer-related-result-type");
+
if (Opts.AppleKext)
Res.push_back("-fapple-kext");
@@ -974,6 +985,7 @@ static void ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args, InputKind IK,
Opts.InstrumentForProfiling = Args.hasArg(OPT_pg);
Opts.EmitGcovArcs = Args.hasArg(OPT_femit_coverage_data);
Opts.EmitGcovNotes = Args.hasArg(OPT_femit_coverage_notes);
+ Opts.CoverageFile = Args.getLastArgValue(OPT_coverage_file);
if (Arg *A = Args.getLastArg(OPT_fobjc_dispatch_method_EQ)) {
llvm::StringRef Name = A->getValue(Args);
@@ -1010,7 +1022,9 @@ static void ParseDiagnosticArgs(DiagnosticOptions &Opts, ArgList &Args,
Opts.PedanticErrors = Args.hasArg(OPT_pedantic_errors);
Opts.ShowCarets = !Args.hasArg(OPT_fno_caret_diagnostics);
Opts.ShowColors = Args.hasArg(OPT_fcolor_diagnostics);
- Opts.ShowColumn = !Args.hasArg(OPT_fno_show_column);
+ Opts.ShowColumn = Args.hasFlag(OPT_fshow_column,
+ OPT_fno_show_column,
+ /*Default=*/true);
Opts.ShowFixits = !Args.hasArg(OPT_fno_diagnostics_fixit_info);
Opts.ShowLocation = !Args.hasArg(OPT_fno_show_source_location);
Opts.ShowNames = Args.hasArg(OPT_fdiagnostics_show_name);
@@ -1047,6 +1061,19 @@ static void ParseDiagnosticArgs(DiagnosticOptions &Opts, ArgList &Args,
<< Args.getLastArg(OPT_fdiagnostics_show_category)->getAsString(Args)
<< ShowCategory;
+ llvm::StringRef Format =
+ Args.getLastArgValue(OPT_fdiagnostics_format, "clang");
+ if (Format == "clang")
+ Opts.Format = DiagnosticOptions::Clang;
+ else if (Format == "msvc")
+ Opts.Format = DiagnosticOptions::Msvc;
+ else if (Format == "vi")
+ Opts.Format = DiagnosticOptions::Vi;
+ else
+ Diags.Report(diag::err_drv_invalid_value)
+ << Args.getLastArg(OPT_fdiagnostics_format)->getAsString(Args)
+ << Format;
+
Opts.ShowSourceRanges = Args.hasArg(OPT_fdiagnostics_print_source_range_info);
Opts.ShowParseableFixits = Args.hasArg(OPT_fdiagnostics_parseable_fixits);
Opts.VerifyDiagnostics = Args.hasArg(OPT_verify);
@@ -1397,6 +1424,40 @@ static void ParseLangArgs(LangOptions &Opts, ArgList &Args, InputKind IK,
if (LangStd == LangStandard::lang_unspecified)
Diags.Report(diag::err_drv_invalid_value)
<< A->getAsString(Args) << A->getValue(Args);
+ else {
+ // Valid standard, check to make sure language and standard are compatable.
+ const LangStandard &Std = LangStandard::getLangStandardForKind(LangStd);
+ switch (IK) {
+ case IK_C:
+ case IK_ObjC:
+ case IK_PreprocessedC:
+ case IK_PreprocessedObjC:
+ if (!(Std.isC89() || Std.isC99()))
+ Diags.Report(diag::err_drv_argument_not_allowed_with)
+ << A->getAsString(Args) << "C/ObjC";
+ break;
+ case IK_CXX:
+ case IK_ObjCXX:
+ case IK_PreprocessedCXX:
+ case IK_PreprocessedObjCXX:
+ if (!Std.isCPlusPlus())
+ Diags.Report(diag::err_drv_argument_not_allowed_with)
+ << A->getAsString(Args) << "C++/ObjC++";
+ break;
+ case IK_OpenCL:
+ if (!Std.isC99())
+ Diags.Report(diag::err_drv_argument_not_allowed_with)
+ << A->getAsString(Args) << "OpenCL";
+ break;
+ case IK_CUDA:
+ if (!Std.isCPlusPlus())
+ Diags.Report(diag::err_drv_argument_not_allowed_with)
+ << A->getAsString(Args) << "CUDA";
+ break;
+ default:
+ break;
+ }
+ }
}
if (const Arg *A = Args.getLastArg(OPT_cl_std_EQ)) {
@@ -1419,11 +1480,17 @@ static void ParseLangArgs(LangOptions &Opts, ArgList &Args, InputKind IK,
if (Args.hasArg(OPT_fno_operator_names))
Opts.CXXOperatorNames = 0;
+ if (Args.hasArg(OPT_fgnu89_inline))
+ Opts.GNUInline = 1;
+
if (Args.hasArg(OPT_fobjc_gc_only))
Opts.setGCMode(LangOptions::GCOnly);
else if (Args.hasArg(OPT_fobjc_gc))
Opts.setGCMode(LangOptions::HybridGC);
+ if (Args.hasArg(OPT_fobjc_infer_related_result_type))
+ Opts.ObjCInferRelatedResultType = 1;
+
if (Args.hasArg(OPT_fapple_kext)) {
if (!Opts.CPlusPlus)
Diags.Report(diag::warn_c_kext);
diff --git a/lib/Frontend/CreateInvocationFromCommandLine.cpp b/lib/Frontend/CreateInvocationFromCommandLine.cpp
index 0005f91..42b648a 100644
--- a/lib/Frontend/CreateInvocationFromCommandLine.cpp
+++ b/lib/Frontend/CreateInvocationFromCommandLine.cpp
@@ -65,7 +65,7 @@ clang::createInvocationFromCommandLine(llvm::ArrayRef<const char *> ArgList,
// We expect to get back exactly one command job, if we didn't something
// failed.
const driver::JobList &Jobs = C->getJobs();
- if (Jobs.size() != 1 || !isa<driver::Command>(Jobs.begin())) {
+ if (Jobs.size() != 1 || !isa<driver::Command>(*Jobs.begin())) {
llvm::SmallString<256> Msg;
llvm::raw_svector_ostream OS(Msg);
C->PrintJob(OS, C->getJobs(), "; ", true);
diff --git a/lib/Frontend/DiagChecker.cpp b/lib/Frontend/DiagChecker.cpp
deleted file mode 100644
index 66d7ed7..0000000
--- a/lib/Frontend/DiagChecker.cpp
+++ /dev/null
@@ -1,301 +0,0 @@
-//===--- DiagChecker.cpp - Diagnostic Checking Functions ------------------===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-//
-// Process the input files and check that the diagnostic messages are expected.
-//
-//===----------------------------------------------------------------------===//
-
-#include "clang/Frontend/Utils.h"
-#include "clang/Frontend/TextDiagnosticBuffer.h"
-#include "clang/Parse/ParseAST.h"
-#include "clang/AST/ASTConsumer.h"
-#include "clang/Basic/SourceManager.h"
-#include "clang/Lex/Preprocessor.h"
-#include "llvm/Support/raw_ostream.h"
-using namespace clang;
-
-typedef TextDiagnosticBuffer::DiagList DiagList;
-typedef TextDiagnosticBuffer::const_iterator const_diag_iterator;
-
-static void EmitError(Preprocessor &PP, SourceLocation Pos, const char *String){
- unsigned ID = PP.getDiagnostics().getCustomDiagID(Diagnostic::Error, String);
- PP.Diag(Pos, ID);
-}
-
-
-// USING THE DIAGNOSTIC CHECKER:
-//
-// Indicating that a line expects an error or a warning is simple. Put a comment
-// on the line that has the diagnostic, use "expected-{error,warning}" to tag
-// if it's an expected error or warning, and place the expected text between {{
-// and }} markers. The full text doesn't have to be included, only enough to
-// ensure that the correct diagnostic was emitted.
-//
-// Here's an example:
-//
-// int A = B; // expected-error {{use of undeclared identifier 'B'}}
-//
-// You can place as many diagnostics on one line as you wish. To make the code
-// more readable, you can use slash-newline to separate out the diagnostics.
-//
-// The simple syntax above allows each specification to match exactly one error.
-// You can use the extended syntax to customize this. The extended syntax is
-// "expected-<type> <n> {{diag text}}", where <type> is one of "error",
-// "warning" or "note", and <n> is a positive integer. This allows the
-// diagnostic to appear as many times as specified. Example:
-//
-// void f(); // expected-note 2 {{previous declaration is here}}
-//
-
-/// FindDiagnostics - Go through the comment and see if it indicates expected
-/// diagnostics. If so, then put them in a diagnostic list.
-///
-static void FindDiagnostics(const char *CommentStart, unsigned CommentLen,
- DiagList &ExpectedDiags,
- Preprocessor &PP, SourceLocation Pos,
- const char *ExpectedStr) {
- const char *CommentEnd = CommentStart+CommentLen;
- unsigned ExpectedStrLen = strlen(ExpectedStr);
-
- // Find all expected-foo diagnostics in the string and add them to
- // ExpectedDiags.
- while (CommentStart != CommentEnd) {
- CommentStart = std::find(CommentStart, CommentEnd, 'e');
- if (unsigned(CommentEnd-CommentStart) < ExpectedStrLen) return;
-
- // If this isn't expected-foo, ignore it.
- if (memcmp(CommentStart, ExpectedStr, ExpectedStrLen)) {
- ++CommentStart;
- continue;
- }
-
- CommentStart += ExpectedStrLen;
-
- // Skip whitespace.
- while (CommentStart != CommentEnd &&
- isspace(CommentStart[0]))
- ++CommentStart;
-
- // Default, if we find the '{' now, is 1 time.
- int Times = 1;
- int Temp = 0;
- // In extended syntax, there could be a digit now.
- while (CommentStart != CommentEnd &&
- CommentStart[0] >= '0' && CommentStart[0] <= '9') {
- Temp *= 10;
- Temp += CommentStart[0] - '0';
- ++CommentStart;
- }
- if (Temp > 0)
- Times = Temp;
-
- // Skip whitespace again.
- while (CommentStart != CommentEnd &&
- isspace(CommentStart[0]))
- ++CommentStart;
-
- // We should have a {{ now.
- if (CommentEnd-CommentStart < 2 ||
- CommentStart[0] != '{' || CommentStart[1] != '{') {
- if (std::find(CommentStart, CommentEnd, '{') != CommentEnd)
- EmitError(PP, Pos, "bogus characters before '{{' in expected string");
- else
- EmitError(PP, Pos, "cannot find start ('{{') of expected string");
- return;
- }
- CommentStart += 2;
-
- // Find the }}.
- const char *ExpectedEnd = CommentStart;
- while (1) {
- ExpectedEnd = std::find(ExpectedEnd, CommentEnd, '}');
- if (CommentEnd-ExpectedEnd < 2) {
- EmitError(PP, Pos, "cannot find end ('}}') of expected string");
- return;
- }
-
- if (ExpectedEnd[1] == '}')
- break;
-
- ++ExpectedEnd; // Skip over singular }'s
- }
-
- std::string Msg(CommentStart, ExpectedEnd);
- std::string::size_type FindPos;
- while ((FindPos = Msg.find("\\n")) != std::string::npos)
- Msg.replace(FindPos, 2, "\n");
- // Add is possibly multiple times.
- for (int i = 0; i < Times; ++i)
- ExpectedDiags.push_back(std::make_pair(Pos, Msg));
-
- CommentStart = ExpectedEnd;
- }
-}
-
-/// FindExpectedDiags - Lex the main source file to find all of the
-// expected errors and warnings.
-static void FindExpectedDiags(Preprocessor &PP,
- DiagList &ExpectedErrors,
- DiagList &ExpectedWarnings,
- DiagList &ExpectedNotes) {
- // Create a raw lexer to pull all the comments out of the main file. We don't
- // want to look in #include'd headers for expected-error strings.
- FileID FID = PP.getSourceManager().getMainFileID();
-
- // Create a lexer to lex all the tokens of the main file in raw mode.
- const llvm::MemoryBuffer *FromFile = PP.getSourceManager().getBuffer(FID);
- Lexer RawLex(FID, FromFile, PP.getSourceManager(), PP.getLangOptions());
-
- // Return comments as tokens, this is how we find expected diagnostics.
- RawLex.SetCommentRetentionState(true);
-
- Token Tok;
- Tok.setKind(tok::comment);
- while (Tok.isNot(tok::eof)) {
- RawLex.Lex(Tok);
- if (!Tok.is(tok::comment)) continue;
-
- std::string Comment = PP.getSpelling(Tok);
- if (Comment.empty()) continue;
-
-
- // Find all expected errors.
- FindDiagnostics(&Comment[0], Comment.size(), ExpectedErrors, PP,
- Tok.getLocation(), "expected-error");
-
- // Find all expected warnings.
- FindDiagnostics(&Comment[0], Comment.size(), ExpectedWarnings, PP,
- Tok.getLocation(), "expected-warning");
-
- // Find all expected notes.
- FindDiagnostics(&Comment[0], Comment.size(), ExpectedNotes, PP,
- Tok.getLocation(), "expected-note");
- };
-}
-
-/// PrintProblem - This takes a diagnostic map of the delta between expected and
-/// seen diagnostics. If there's anything in it, then something unexpected
-/// happened. Print the map out in a nice format and return "true". If the map
-/// is empty and we're not going to print things, then return "false".
-///
-static bool PrintProblem(SourceManager &SourceMgr,
- const_diag_iterator diag_begin,
- const_diag_iterator diag_end,
- const char *Msg) {
- if (diag_begin == diag_end) return false;
-
- llvm::errs() << Msg << "\n";
- for (const_diag_iterator I = diag_begin, E = diag_end; I != E; ++I)
- llvm::errs() << " Line " << SourceMgr.getInstantiationLineNumber(I->first)
- << " " << I->second << "\n";
-
- return true;
-}
-
-/// CompareDiagLists - Compare two diagnostic lists and return the difference
-/// between them.
-///
-static bool CompareDiagLists(SourceManager &SourceMgr,
- const_diag_iterator d1_begin,
- const_diag_iterator d1_end,
- const_diag_iterator d2_begin,
- const_diag_iterator d2_end,
- const char *MsgLeftOnly,
- const char *MsgRightOnly) {
- DiagList LeftOnly;
- DiagList Left(d1_begin, d1_end);
- DiagList Right(d2_begin, d2_end);
-
- for (const_diag_iterator I = Left.begin(), E = Left.end(); I != E; ++I) {
- unsigned LineNo1 = SourceMgr.getInstantiationLineNumber(I->first);
- const std::string &Diag1 = I->second;
-
- DiagList::iterator II, IE;
- for (II = Right.begin(), IE = Right.end(); II != IE; ++II) {
- unsigned LineNo2 = SourceMgr.getInstantiationLineNumber(II->first);
- if (LineNo1 != LineNo2) continue;
-
- const std::string &Diag2 = II->second;
- if (Diag2.find(Diag1) != std::string::npos ||
- Diag1.find(Diag2) != std::string::npos) {
- break;
- }
- }
- if (II == IE) {
- // Not found.
- LeftOnly.push_back(*I);
- } else {
- // Found. The same cannot be found twice.
- Right.erase(II);
- }
- }
- // Now all that's left in Right are those that were not matched.
-
- return PrintProblem(SourceMgr, LeftOnly.begin(), LeftOnly.end(), MsgLeftOnly)
- | PrintProblem(SourceMgr, Right.begin(), Right.end(), MsgRightOnly);
-}
-
-/// CheckResults - This compares the expected results to those that
-/// were actually reported. It emits any discrepencies. Return "true" if there
-/// were problems. Return "false" otherwise.
-///
-static bool CheckResults(Preprocessor &PP,
- const DiagList &ExpectedErrors,
- const DiagList &ExpectedWarnings,
- const DiagList &ExpectedNotes) {
- const DiagnosticClient *DiagClient = PP.getDiagnostics().getClient();
- assert(DiagClient != 0 &&
- "DiagChecker requires a valid TextDiagnosticBuffer");
- const TextDiagnosticBuffer &Diags =
- static_cast<const TextDiagnosticBuffer&>(*DiagClient);
- SourceManager &SourceMgr = PP.getSourceManager();
-
- // We want to capture the delta between what was expected and what was
- // seen.
- //
- // Expected \ Seen - set expected but not seen
- // Seen \ Expected - set seen but not expected
- bool HadProblem = false;
-
- // See if there are error mismatches.
- HadProblem |= CompareDiagLists(SourceMgr,
- ExpectedErrors.begin(), ExpectedErrors.end(),
- Diags.err_begin(), Diags.err_end(),
- "Errors expected but not seen:",
- "Errors seen but not expected:");
-
- // See if there are warning mismatches.
- HadProblem |= CompareDiagLists(SourceMgr,
- ExpectedWarnings.begin(),
- ExpectedWarnings.end(),
- Diags.warn_begin(), Diags.warn_end(),
- "Warnings expected but not seen:",
- "Warnings seen but not expected:");
-
- // See if there are note mismatches.
- HadProblem |= CompareDiagLists(SourceMgr,
- ExpectedNotes.begin(),
- ExpectedNotes.end(),
- Diags.note_begin(), Diags.note_end(),
- "Notes expected but not seen:",
- "Notes seen but not expected:");
-
- return HadProblem;
-}
-
-
-/// CheckDiagnostics - Gather the expected diagnostics and check them.
-bool clang::CheckDiagnostics(Preprocessor &PP) {
- // Gather the set of expected diagnostics.
- DiagList ExpectedErrors, ExpectedWarnings, ExpectedNotes;
- FindExpectedDiags(PP, ExpectedErrors, ExpectedWarnings, ExpectedNotes);
-
- // Check that the expected diagnostics occurred.
- return CheckResults(PP, ExpectedErrors, ExpectedWarnings, ExpectedNotes);
-}
diff --git a/lib/Frontend/InitHeaderSearch.cpp b/lib/Frontend/InitHeaderSearch.cpp
index c552512..ad93116 100644
--- a/lib/Frontend/InitHeaderSearch.cpp
+++ b/lib/Frontend/InitHeaderSearch.cpp
@@ -559,6 +559,19 @@ void InitHeaderSearch::AddDefaultCIncludePaths(const llvm::Triple &triple,
AddPath("/mingw/include", System, true, false, false);
AddPath("c:/mingw/include", System, true, false, false);
break;
+ case llvm::Triple::Linux:
+ // Generic Debian multiarch support:
+ if (triple.getArch() == llvm::Triple::x86_64) {
+ AddPath("/usr/include/x86_64-linux-gnu", System, false, false, false);
+ AddPath("/usr/include/i686-linux-gnu/64", System, false, false, false);
+ AddPath("/usr/include/i486-linux-gnu/64", System, false, false, false);
+ } else if (triple.getArch() == llvm::Triple::x86) {
+ AddPath("/usr/include/x86_64-linux-gnu/32", System, false, false, false);
+ AddPath("/usr/include/i686-linux-gnu", System, false, false, false);
+ AddPath("/usr/include/i486-linux-gnu", System, false, false, false);
+ } else if (triple.getArch() == llvm::Triple::arm) {
+ AddPath("/usr/include/arm-linux-gnueabi", System, false, false, false);
+ }
default:
break;
}
@@ -651,6 +664,27 @@ AddDefaultCPlusPlusIncludePaths(const llvm::Triple &triple) {
// Debian based distros.
// Note: these distros symlink /usr/include/c++/X.Y.Z -> X.Y
//===------------------------------------------------------------------===//
+
+ // Ubuntu 11.11 "Oneiric Ocelot" -- gcc-4.6.0
+ AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.6",
+ "x86_64-linux-gnu", "32", "", triple);
+ AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.6",
+ "i686-linux-gnu", "", "64", triple);
+ AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.6",
+ "i486-linux-gnu", "", "64", triple);
+ AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.6",
+ "arm-linux-gnueabi", "", "", triple);
+
+ // Ubuntu 11.04 "Natty Narwhal" -- gcc-4.5.2
+ AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.5",
+ "x86_64-linux-gnu", "32", "", triple);
+ AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.5",
+ "i686-linux-gnu", "", "64", triple);
+ AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.5",
+ "i486-linux-gnu", "", "64", triple);
+ AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.5",
+ "arm-linux-gnueabi", "", "", triple);
+
// Ubuntu 10.10 "Maverick Meerkat" -- gcc-4.4.5
AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.4",
"i686-linux-gnu", "", "64", triple);
@@ -734,6 +768,13 @@ AddDefaultCPlusPlusIncludePaths(const llvm::Triple &triple) {
"x86_64-redhat-linux", "", "", triple);
AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.1.2",
"i386-redhat-linux", "", "", triple);
+
+ // RHEL 5
+ AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.1.1",
+ "x86_64-redhat-linux", "32", "", triple);
+ AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.1.1",
+ "i386-redhat-linux", "", "", triple);
+
//===------------------------------------------------------------------===//
@@ -761,6 +802,11 @@ AddDefaultCPlusPlusIncludePaths(const llvm::Triple &triple) {
AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.5",
"x86_64-suse-linux", "", "", triple);
+ // openSUSE 12.1
+ AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.6",
+ "i586-suse-linux", "", "", triple);
+ AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.6",
+ "x86_64-suse-linux", "", "", triple);
// Arch Linux 2008-06-24
AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.3.1",
"i686-pc-linux-gnu", "", "", triple);
@@ -986,6 +1032,8 @@ void InitHeaderSearch::Realize(const LangOptions &Lang) {
if (it->first == Angled)
SearchList.push_back(it->second);
}
+ RemoveDuplicates(SearchList, quoted, Verbose);
+ unsigned angled = SearchList.size();
for (path_iterator it = IncludePath.begin(), ie = IncludePath.end();
it != ie; ++it) {
@@ -999,10 +1047,10 @@ void InitHeaderSearch::Realize(const LangOptions &Lang) {
SearchList.push_back(it->second);
}
- RemoveDuplicates(SearchList, quoted, Verbose);
+ RemoveDuplicates(SearchList, angled, Verbose);
bool DontSearchCurDir = false; // TODO: set to true if -I- is set?
- Headers.SetSearchPaths(SearchList, quoted, DontSearchCurDir);
+ Headers.SetSearchPaths(SearchList, quoted, angled, DontSearchCurDir);
// If verbose, print the list of directories that will be searched.
if (Verbose) {
diff --git a/lib/Frontend/InitPreprocessor.cpp b/lib/Frontend/InitPreprocessor.cpp
index abe251d..147a8df0 100644
--- a/lib/Frontend/InitPreprocessor.cpp
+++ b/lib/Frontend/InitPreprocessor.cpp
@@ -221,6 +221,40 @@ static void DefineExactWidthIntType(TargetInfo::IntType Ty,
ConstSuffix);
}
+static void InitializeStandardPredefinedMacros(const TargetInfo &TI,
+ const LangOptions &LangOpts,
+ const FrontendOptions &FEOpts,
+ MacroBuilder &Builder) {
+ if (!LangOpts.Microsoft && !LangOpts.TraditionalCPP)
+ Builder.defineMacro("__STDC__");
+ if (LangOpts.Freestanding)
+ Builder.defineMacro("__STDC_HOSTED__", "0");
+ else
+ Builder.defineMacro("__STDC_HOSTED__");
+
+ if (!LangOpts.CPlusPlus) {
+ if (LangOpts.C99)
+ Builder.defineMacro("__STDC_VERSION__", "199901L");
+ else if (!LangOpts.GNUMode && LangOpts.Digraphs)
+ Builder.defineMacro("__STDC_VERSION__", "199409L");
+ } else {
+ if (LangOpts.GNUMode)
+ Builder.defineMacro("__cplusplus");
+ else
+ // C++ [cpp.predefined]p1:
+ // The name_ _cplusplus is defined to the value 199711L when compiling a
+ // C++ translation unit.
+ Builder.defineMacro("__cplusplus", "199711L");
+ }
+
+ if (LangOpts.ObjC1)
+ Builder.defineMacro("__OBJC__");
+
+ // Not "standard" per se, but available even with the -undef flag.
+ if (LangOpts.AsmPreprocessor)
+ Builder.defineMacro("__ASSEMBLER__");
+}
+
static void InitializePredefinedMacros(const TargetInfo &TI,
const LangOptions &LangOpts,
const FrontendOptions &FEOpts,
@@ -256,20 +290,6 @@ static void InitializePredefinedMacros(const TargetInfo &TI,
// Initialize language-specific preprocessor defines.
- // These should all be defined in the preprocessor according to the
- // current language configuration.
- if (!LangOpts.Microsoft && !LangOpts.TraditionalCPP)
- Builder.defineMacro("__STDC__");
- if (LangOpts.AsmPreprocessor)
- Builder.defineMacro("__ASSEMBLER__");
-
- if (!LangOpts.CPlusPlus) {
- if (LangOpts.C99)
- Builder.defineMacro("__STDC_VERSION__", "199901L");
- else if (!LangOpts.GNUMode && LangOpts.Digraphs)
- Builder.defineMacro("__STDC_VERSION__", "199409L");
- }
-
// Standard conforming mode?
if (!LangOpts.GNUMode)
Builder.defineMacro("__STRICT_ANSI__");
@@ -277,13 +297,7 @@ static void InitializePredefinedMacros(const TargetInfo &TI,
if (LangOpts.CPlusPlus0x)
Builder.defineMacro("__GXX_EXPERIMENTAL_CXX0X__");
- if (LangOpts.Freestanding)
- Builder.defineMacro("__STDC_HOSTED__", "0");
- else
- Builder.defineMacro("__STDC_HOSTED__");
-
if (LangOpts.ObjC1) {
- Builder.defineMacro("__OBJC__");
if (LangOpts.ObjCNonFragileABI) {
Builder.defineMacro("__OBJC2__");
Builder.defineMacro("OBJC_ZEROCOST_EXCEPTIONS");
@@ -324,13 +338,6 @@ static void InitializePredefinedMacros(const TargetInfo &TI,
if (LangOpts.CPlusPlus) {
Builder.defineMacro("__GNUG__", "4");
Builder.defineMacro("__GXX_WEAK__");
- if (LangOpts.GNUMode)
- Builder.defineMacro("__cplusplus");
- else
- // C++ [cpp.predefined]p1:
- // The name_ _cplusplusis defined to the value 199711L when compiling a
- // C++ translation unit.
- Builder.defineMacro("__cplusplus", "199711L");
Builder.defineMacro("__private_extern__", "extern");
}
@@ -343,6 +350,8 @@ static void InitializePredefinedMacros(const TargetInfo &TI,
// Since we define wchar_t in C++ mode.
Builder.defineMacro("_WCHAR_T_DEFINED");
Builder.defineMacro("_NATIVE_WCHAR_T_DEFINED");
+ // FIXME: Support Microsoft's __identifier extension in the lexer.
+ Builder.append("#define __identifier(x) x");
Builder.append("class type_info;");
}
@@ -570,6 +579,12 @@ void clang::InitializePreprocessor(Preprocessor &PP,
InitializePredefinedMacros(PP.getTargetInfo(), PP.getLangOptions(),
FEOpts, Builder);
+ // Even with predefines off, some macros are still predefined.
+ // These should all be defined in the preprocessor according to the
+ // current language configuration.
+ InitializeStandardPredefinedMacros(PP.getTargetInfo(), PP.getLangOptions(),
+ FEOpts, Builder);
+
// Add on the predefines from the driver. Wrap in a #line directive to report
// that they come from the command line.
if (!PP.getLangOptions().AsmPreprocessor)
diff --git a/lib/Frontend/LogDiagnosticPrinter.cpp b/lib/Frontend/LogDiagnosticPrinter.cpp
index 954bad4..78eb1b2 100644
--- a/lib/Frontend/LogDiagnosticPrinter.cpp
+++ b/lib/Frontend/LogDiagnosticPrinter.cpp
@@ -99,7 +99,7 @@ void LogDiagnosticPrinter::HandleDiagnostic(Diagnostic::Level Level,
DiagnosticClient::HandleDiagnostic(Level, Info);
// Initialize the main file name, if we haven't already fetched it.
- if (MainFilename.empty()) {
+ if (MainFilename.empty() && Info.hasSourceManager()) {
const SourceManager &SM = Info.getSourceManager();
FileID FID = SM.getMainFileID();
if (!FID.isInvalid()) {
@@ -122,7 +122,7 @@ void LogDiagnosticPrinter::HandleDiagnostic(Diagnostic::Level Level,
// Set the location information.
DE.Filename = "";
DE.Line = DE.Column = 0;
- if (Info.getLocation().isValid()) {
+ if (Info.getLocation().isValid() && Info.hasSourceManager()) {
const SourceManager &SM = Info.getSourceManager();
PresumedLoc PLoc = SM.getPresumedLoc(Info.getLocation());
diff --git a/lib/Frontend/TextDiagnosticPrinter.cpp b/lib/Frontend/TextDiagnosticPrinter.cpp
index 47c942c..1c47bf7 100644
--- a/lib/Frontend/TextDiagnosticPrinter.cpp
+++ b/lib/Frontend/TextDiagnosticPrinter.cpp
@@ -343,7 +343,7 @@ void TextDiagnosticPrinter::EmitCaretDiagnostic(Diagnostic::Level Level,
// "included from" lines.
if (LastWarningLoc != PLoc.getIncludeLoc()) {
LastWarningLoc = PLoc.getIncludeLoc();
- PrintIncludeStack(Level, LastWarningLoc, SM);
+ PrintIncludeStack(Diagnostic::Note, LastWarningLoc, SM);
}
if (DiagOpts->ShowLocation) {
@@ -819,16 +819,28 @@ void TextDiagnosticPrinter::HandleDiagnostic(Diagnostic::Level Level,
if (DiagOpts->ShowColors)
OS.changeColor(savedColor, true);
- // Emit a Visual Studio compatible line number syntax.
- if (LangOpts && LangOpts->Microsoft) {
- OS << PLoc.getFilename() << '(' << LineNo << ')';
- OS << " : ";
- } else {
- OS << PLoc.getFilename() << ':' << LineNo << ':';
- if (DiagOpts->ShowColumn)
- if (unsigned ColNo = PLoc.getColumn())
- OS << ColNo << ':';
+ OS << PLoc.getFilename();
+ switch (DiagOpts->Format) {
+ case DiagnosticOptions::Clang: OS << ':' << LineNo; break;
+ case DiagnosticOptions::Msvc: OS << '(' << LineNo; break;
+ case DiagnosticOptions::Vi: OS << " +" << LineNo; break;
+ }
+ if (DiagOpts->ShowColumn)
+ if (unsigned ColNo = PLoc.getColumn()) {
+ if (DiagOpts->Format == DiagnosticOptions::Msvc) {
+ OS << ',';
+ ColNo--;
+ } else
+ OS << ':';
+ OS << ColNo;
+ }
+ switch (DiagOpts->Format) {
+ case DiagnosticOptions::Clang:
+ case DiagnosticOptions::Vi: OS << ':'; break;
+ case DiagnosticOptions::Msvc: OS << ") : "; break;
}
+
+
if (DiagOpts->ShowSourceRanges && Info.getNumRanges()) {
FileID CaretFileID =
SM.getFileID(SM.getInstantiationLoc(Info.getLocation()));
@@ -927,8 +939,8 @@ void TextDiagnosticPrinter::HandleDiagnostic(Diagnostic::Level Level,
OptionName += "-Werror";
}
- if (const char *
- Opt = DiagnosticIDs::getWarningOptionForDiag(Info.getID())) {
+ llvm::StringRef Opt = DiagnosticIDs::getWarningOptionForDiag(Info.getID());
+ if (!Opt.empty()) {
if (!OptionName.empty())
OptionName += ',';
OptionName += "-W";
diff --git a/lib/Frontend/Warnings.cpp b/lib/Frontend/Warnings.cpp
index 8cc5616..f12b484 100644
--- a/lib/Frontend/Warnings.cpp
+++ b/lib/Frontend/Warnings.cpp
@@ -55,17 +55,14 @@ void clang::ProcessWarningOptions(Diagnostic &Diags,
Diags.setExtensionHandlingBehavior(Diagnostic::Ext_Ignore);
for (unsigned i = 0, e = Opts.Warnings.size(); i != e; ++i) {
- const std::string &Opt = Opts.Warnings[i];
- const char *OptStart = &Opt[0];
- const char *OptEnd = OptStart+Opt.size();
- assert(*OptEnd == 0 && "Expect null termination for lower-bound search");
+ llvm::StringRef Opt = Opts.Warnings[i];
// Check to see if this warning starts with "no-", if so, this is a negative
// form of the option.
bool isPositive = true;
- if (OptEnd-OptStart > 3 && memcmp(OptStart, "no-", 3) == 0) {
+ if (Opt.startswith("no-")) {
isPositive = false;
- OptStart += 3;
+ Opt = Opt.substr(3);
}
// Figure out how this option affects the warning. If -Wfoo, map the
@@ -74,49 +71,47 @@ void clang::ProcessWarningOptions(Diagnostic &Diags,
// -Wsystem-headers is a special case, not driven by the option table. It
// cannot be controlled with -Werror.
- if (OptEnd-OptStart == 14 && memcmp(OptStart, "system-headers", 14) == 0) {
+ if (Opt == "system-headers") {
Diags.setSuppressSystemWarnings(!isPositive);
continue;
}
// -Werror/-Wno-error is a special case, not controlled by the option table.
// It also has the "specifier" form of -Werror=foo and -Werror-foo.
- if (OptEnd-OptStart >= 5 && memcmp(OptStart, "error", 5) == 0) {
- const char *Specifier = 0;
- if (OptEnd-OptStart != 5) { // Specifier must be present.
- if ((OptStart[5] != '=' && OptStart[5] != '-') ||
- OptEnd-OptStart == 6) {
+ if (Opt.startswith("error")) {
+ llvm::StringRef Specifier;
+ if (Opt.size() > 5) { // Specifier must be present.
+ if ((Opt[5] != '=' && Opt[5] != '-') || Opt.size() == 6) {
Diags.Report(diag::warn_unknown_warning_specifier)
- << "-Werror" << ("-W" + Opt);
+ << "-Werror" << ("-W" + Opt.str());
continue;
}
- Specifier = OptStart+6;
+ Specifier = Opt.substr(6);
}
- if (Specifier == 0) {
+ if (Specifier.empty()) {
Diags.setWarningsAsErrors(isPositive);
continue;
}
// -Werror=foo maps foo to Error, -Wno-error=foo maps it to Warning.
Mapping = isPositive ? diag::MAP_ERROR : diag::MAP_WARNING_NO_WERROR;
- OptStart = Specifier;
+ Opt = Specifier;
}
// -Wfatal-errors is yet another special case.
- if (OptEnd-OptStart >= 12 && memcmp(OptStart, "fatal-errors", 12) == 0) {
- const char* Specifier = 0;
- if (OptEnd-OptStart != 12) {
- if ((OptStart[12] != '=' && OptStart[12] != '-') ||
- OptEnd-OptStart == 13) {
+ if (Opt.startswith("fatal-errors")) {
+ llvm::StringRef Specifier;
+ if (Opt.size() != 12) {
+ if ((Opt[12] != '=' && Opt[12] != '-') || Opt.size() == 13) {
Diags.Report(diag::warn_unknown_warning_specifier)
- << "-Wfatal-errors" << ("-W" + Opt);
+ << "-Wfatal-errors" << ("-W" + Opt.str());
continue;
}
- Specifier = OptStart + 13;
+ Specifier = Opt.substr(13);
}
- if (Specifier == 0) {
+ if (Specifier.empty()) {
Diags.setErrorsAsFatal(isPositive);
continue;
}
@@ -124,10 +119,12 @@ void clang::ProcessWarningOptions(Diagnostic &Diags,
// -Wfatal-errors=foo maps foo to Fatal, -Wno-fatal-errors=foo
// maps it to Error.
Mapping = isPositive ? diag::MAP_FATAL : diag::MAP_ERROR_NO_WFATAL;
- OptStart = Specifier;
+ Opt = Specifier;
}
- if (Diags.setDiagnosticGroupMapping(OptStart, Mapping))
- Diags.Report(diag::warn_unknown_warning_option) << ("-W" + Opt);
+ if (Diags.setDiagnosticGroupMapping(Opt, Mapping))
+ Diags.Report(isPositive ? diag::warn_unknown_warning_option :
+ diag::warn_unknown_negative_warning_option)
+ << ("-W" + Opt.str());
}
}
diff --git a/lib/Headers/emmintrin.h b/lib/Headers/emmintrin.h
index 0c1d730..ee12d3c 100644
--- a/lib/Headers/emmintrin.h
+++ b/lib/Headers/emmintrin.h
@@ -466,7 +466,10 @@ _mm_loadr_pd(double const *dp)
static __inline__ __m128d __attribute__((__always_inline__, __nodebug__))
_mm_loadu_pd(double const *dp)
{
- return (__m128d){ dp[0], dp[1] };
+ struct __loadu_pd {
+ __m128d v;
+ } __attribute__((packed, may_alias));
+ return ((struct __loadu_pd*)dp)->v;
}
static __inline__ __m128d __attribute__((__always_inline__, __nodebug__))
@@ -478,13 +481,13 @@ _mm_load_sd(double const *dp)
static __inline__ __m128d __attribute__((__always_inline__, __nodebug__))
_mm_loadh_pd(__m128d a, double const *dp)
{
- return __builtin_shufflevector(a, *(__m128d *)dp, 0, 2);
+ return (__m128d){ a[0], *dp };
}
static __inline__ __m128d __attribute__((__always_inline__, __nodebug__))
_mm_loadl_pd(__m128d a, double const *dp)
{
- return __builtin_shufflevector(a, *(__m128d *)dp, 2, 1);
+ return (__m128d){ *dp, a[1] };
}
static __inline__ __m128d __attribute__((__always_inline__, __nodebug__))
@@ -1011,7 +1014,10 @@ _mm_load_si128(__m128i const *p)
static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
_mm_loadu_si128(__m128i const *p)
{
- return (__m128i)__builtin_ia32_loaddqu((char const *)p);
+ struct __loadu_si128 {
+ __m128i v;
+ } __attribute__((packed, may_alias));
+ return ((struct __loadu_si128*)p)->v;
}
static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
diff --git a/lib/Headers/mmintrin.h b/lib/Headers/mmintrin.h
index fefb42f..986870a 100644
--- a/lib/Headers/mmintrin.h
+++ b/lib/Headers/mmintrin.h
@@ -421,20 +421,20 @@ _mm_set1_pi8(char __b)
}
static __inline__ __m64 __attribute__((__always_inline__, __nodebug__))
-_mm_setr_pi32(int __i1, int __i0)
+_mm_setr_pi32(int __i0, int __i1)
{
return _mm_set_pi32(__i1, __i0);
}
static __inline__ __m64 __attribute__((__always_inline__, __nodebug__))
-_mm_setr_pi16(short __w3, short __w2, short __w1, short __w0)
+_mm_setr_pi16(short __w0, short __w1, short __w2, short __w3)
{
return _mm_set_pi16(__w3, __w2, __w1, __w0);
}
static __inline__ __m64 __attribute__((__always_inline__, __nodebug__))
-_mm_setr_pi8(char __b7, char __b6, char __b5, char __b4, char __b3, char __b2,
- char __b1, char __b0)
+_mm_setr_pi8(char __b0, char __b1, char __b2, char __b3, char __b4, char __b5,
+ char __b6, char __b7)
{
return _mm_set_pi8(__b7, __b6, __b5, __b4, __b3, __b2, __b1, __b0);
}
diff --git a/lib/Headers/xmmintrin.h b/lib/Headers/xmmintrin.h
index 00760ed..50f275d 100644
--- a/lib/Headers/xmmintrin.h
+++ b/lib/Headers/xmmintrin.h
@@ -539,7 +539,10 @@ _mm_load_ps(const float *p)
static __inline__ __m128 __attribute__((__always_inline__, __nodebug__))
_mm_loadu_ps(const float *p)
{
- return (__m128){ p[0], p[1], p[2], p[3] };
+ struct __loadu_ps {
+ __m128 v;
+ } __attribute__((packed, may_alias));
+ return ((struct __loadu_ps*)p)->v;
}
static __inline__ __m128 __attribute__((__always_inline__, __nodebug__))
diff --git a/lib/Index/CallGraph.cpp b/lib/Index/CallGraph.cpp
index bf3f5a8..94790b8 100644
--- a/lib/Index/CallGraph.cpp
+++ b/lib/Index/CallGraph.cpp
@@ -74,7 +74,7 @@ void CallGraph::addTU(ASTContext& Ctx) {
I != E; ++I) {
if (FunctionDecl *FD = dyn_cast<FunctionDecl>(*I)) {
- if (FD->isThisDeclarationADefinition()) {
+ if (FD->doesThisDeclarationHaveABody()) {
// Set caller's ASTContext.
Entity Ent = Entity::get(FD, Prog);
CallGraphNode *Node = getOrInsertFunction(Ent);
diff --git a/lib/Index/Indexer.cpp b/lib/Index/Indexer.cpp
index 7f21c4f..ebba43c 100644
--- a/lib/Index/Indexer.cpp
+++ b/lib/Index/Indexer.cpp
@@ -39,7 +39,7 @@ public:
Decl *D = Ent.getDecl(TU->getASTContext());
if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D))
- if (FD->isThisDeclarationADefinition())
+ if (FD->doesThisDeclarationHaveABody())
DefMap[Ent] = std::make_pair(FD, TU);
}
};
diff --git a/lib/Lex/HeaderSearch.cpp b/lib/Lex/HeaderSearch.cpp
index 372078c..bb43881 100644
--- a/lib/Lex/HeaderSearch.cpp
+++ b/lib/Lex/HeaderSearch.cpp
@@ -37,6 +37,7 @@ ExternalHeaderFileInfoSource::~ExternalHeaderFileInfoSource() {}
HeaderSearch::HeaderSearch(FileManager &FM)
: FileMgr(FM), FrameworkMap(64) {
+ AngledDirIdx = 0;
SystemDirIdx = 0;
NoCurDirSearch = false;
@@ -317,7 +318,7 @@ const FileEntry *HeaderSearch::LookupFile(
CurDir = 0;
// If this is a system #include, ignore the user #include locs.
- unsigned i = isAngled ? SystemDirIdx : 0;
+ unsigned i = isAngled ? AngledDirIdx : 0;
// If this is a #include_next request, start searching after the directory the
// file was found in.
@@ -482,6 +483,21 @@ HeaderFileInfo &HeaderSearch::getFileInfo(const FileEntry *FE) {
return HFI;
}
+bool HeaderSearch::isFileMultipleIncludeGuarded(const FileEntry *File) {
+ // Check if we've ever seen this file as a header.
+ if (File->getUID() >= FileInfo.size())
+ return false;
+
+ // Resolve header file info from the external source, if needed.
+ HeaderFileInfo &HFI = FileInfo[File->getUID()];
+ if (ExternalSource && !HFI.Resolved) {
+ HFI = ExternalSource->GetHeaderFileInfo(File);
+ HFI.Resolved = true;
+ }
+
+ return HFI.isPragmaOnce || HFI.ControllingMacro || HFI.ControllingMacroID;
+}
+
void HeaderSearch::setHeaderFileInfoForUID(HeaderFileInfo HFI, unsigned UID) {
if (UID >= FileInfo.size())
FileInfo.resize(UID+1);
diff --git a/lib/Lex/Lexer.cpp b/lib/Lex/Lexer.cpp
index 16cc4f8..3b1149c 100644
--- a/lib/Lex/Lexer.cpp
+++ b/lib/Lex/Lexer.cpp
@@ -76,7 +76,8 @@ void Lexer::InitLexer(const char *BufStart, const char *BufPtr,
// skip the UTF-8 BOM if it's present.
if (BufferStart == BufferPtr) {
// Determine the size of the BOM.
- size_t BOMLength = llvm::StringSwitch<size_t>(BufferStart)
+ llvm::StringRef Buf(BufferStart, BufferEnd - BufferStart);
+ size_t BOMLength = llvm::StringSwitch<size_t>(Buf)
.StartsWith("\xEF\xBB\xBF", 3) // UTF-8 BOM
.Default(0);
diff --git a/lib/Lex/LiteralSupport.cpp b/lib/Lex/LiteralSupport.cpp
index 37e7bf4..2c96c4d 100644
--- a/lib/Lex/LiteralSupport.cpp
+++ b/lib/Lex/LiteralSupport.cpp
@@ -840,16 +840,27 @@ StringLiteralParser::
StringLiteralParser(const Token *StringToks, unsigned NumStringToks,
Preprocessor &PP, bool Complain)
: SM(PP.getSourceManager()), Features(PP.getLangOptions()),
- Target(PP.getTargetInfo()), Diags(Complain ? &PP.getDiagnostics() : 0) {
+ Target(PP.getTargetInfo()), Diags(Complain ? &PP.getDiagnostics() : 0),
+ MaxTokenLength(0), SizeBound(0), wchar_tByteWidth(0),
+ ResultPtr(ResultBuf.data()), hadError(false), AnyWide(false), Pascal(false) {
init(StringToks, NumStringToks);
}
void StringLiteralParser::init(const Token *StringToks, unsigned NumStringToks){
+ // The literal token may have come from an invalid source location (e.g. due
+ // to a PCH error), in which case the token length will be 0.
+ if (NumStringToks == 0 || StringToks[0].getLength() < 2) {
+ hadError = true;
+ return;
+ }
+
// 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
// literal, the result is a wide-string literal [C99 6.4.5p4].
+ assert(NumStringToks && "expected at least one token");
MaxTokenLength = StringToks[0].getLength();
+ assert(StringToks[0].getLength() >= 2 && "literal token is invalid!");
SizeBound = StringToks[0].getLength()-2; // -2 for "".
AnyWide = StringToks[0].is(tok::wide_string_literal);
@@ -858,8 +869,14 @@ void StringLiteralParser::init(const Token *StringToks, unsigned NumStringToks){
// Implement Translation Phase #6: concatenation of string literals
/// (C99 5.1.1.2p1). The common case is only one string fragment.
for (unsigned i = 1; i != NumStringToks; ++i) {
+ if (StringToks[i].getLength() < 2) {
+ hadError = true;
+ return;
+ }
+
// The string could be shorter than this if it needs cleaning, but this is a
// reasonable bound, which is all we need.
+ assert(StringToks[i].getLength() >= 2 && "literal token is invalid!");
SizeBound += StringToks[i].getLength()-2; // -2 for "".
// Remember maximum string piece length.
diff --git a/lib/Lex/MacroInfo.cpp b/lib/Lex/MacroInfo.cpp
index c819011..66d87a1 100644
--- a/lib/Lex/MacroInfo.cpp
+++ b/lib/Lex/MacroInfo.cpp
@@ -42,6 +42,7 @@ MacroInfo::MacroInfo(const MacroInfo &MI, llvm::BumpPtrAllocator &PPAllocator) {
IsDisabled = MI.IsDisabled;
IsUsed = MI.IsUsed;
IsAllowRedefinitionsWithoutWarning = MI.IsAllowRedefinitionsWithoutWarning;
+ IsWarnIfUnused = MI.IsWarnIfUnused;
ArgumentList = 0;
NumArguments = 0;
setArgumentList(MI.ArgumentList, MI.NumArguments, PPAllocator);
diff --git a/lib/Lex/PPDirectives.cpp b/lib/Lex/PPDirectives.cpp
index af3fa6e..66e44bb 100644
--- a/lib/Lex/PPDirectives.cpp
+++ b/lib/Lex/PPDirectives.cpp
@@ -323,7 +323,6 @@ void Preprocessor::SkipExcludedConditionalBlock(SourceLocation IfTokenLoc,
// #else directive in a skipping conditional. If not in some other
// skipping conditional, and if #else hasn't already been seen, enter it
// as a non-skipping conditional.
- DiscardUntilEndOfDirective(); // C99 6.10p4.
PPConditionalInfo &CondInfo = CurPPLexer->peekConditionalLevel();
// If this is a #else with a #else before it, report the error.
@@ -339,7 +338,10 @@ void Preprocessor::SkipExcludedConditionalBlock(SourceLocation IfTokenLoc,
// entered, enter the #else block now.
if (!CondInfo.WasSkipping && !CondInfo.FoundNonSkip) {
CondInfo.FoundNonSkip = true;
+ CheckEndOfDirective("else");
break;
+ } else {
+ DiscardUntilEndOfDirective(); // C99 6.10p4.
}
} else if (Sub == "lif") { // "elif".
PPConditionalInfo &CondInfo = CurPPLexer->peekConditionalLevel();
diff --git a/lib/Lex/PPMacroExpansion.cpp b/lib/Lex/PPMacroExpansion.cpp
index d6e0d3a..01cd75f 100644
--- a/lib/Lex/PPMacroExpansion.cpp
+++ b/lib/Lex/PPMacroExpansion.cpp
@@ -85,6 +85,7 @@ void Preprocessor::RegisterBuiltinMacros() {
// Clang Extensions.
Ident__has_feature = RegisterBuiltinMacro(*this, "__has_feature");
+ Ident__has_extension = RegisterBuiltinMacro(*this, "__has_extension");
Ident__has_builtin = RegisterBuiltinMacro(*this, "__has_builtin");
Ident__has_attribute = RegisterBuiltinMacro(*this, "__has_attribute");
Ident__has_include = RegisterBuiltinMacro(*this, "__has_include");
@@ -525,8 +526,8 @@ static void ComputeDATE_TIME(SourceLocation &DATELoc, SourceLocation &TIMELoc,
}
-/// HasFeature - Return true if we recognize and implement the specified feature
-/// specified by the identifier.
+/// HasFeature - Return true if we recognize and implement the feature
+/// specified by the identifier as a standard language feature.
static bool HasFeature(const Preprocessor &PP, const IdentifierInfo *II) {
const LangOptions &LangOpts = PP.getLangOptions();
@@ -550,13 +551,17 @@ static bool HasFeature(const Preprocessor &PP, const IdentifierInfo *II) {
.Case("cxx_exceptions", LangOpts.Exceptions)
.Case("cxx_rtti", LangOpts.RTTI)
.Case("enumerator_attributes", true)
- .Case("generic_selections", true)
.Case("objc_nonfragile_abi", LangOpts.ObjCNonFragileABI)
.Case("objc_weak_class", LangOpts.ObjCNonFragileABI)
.Case("ownership_holds", true)
.Case("ownership_returns", true)
.Case("ownership_takes", true)
+ // C1X features
+ .Case("c_generic_selections", LangOpts.C1X)
+ .Case("c_static_assert", LangOpts.C1X)
// C++0x features
+ .Case("cxx_access_control_sfinae", LangOpts.CPlusPlus0x)
+ .Case("cxx_alias_templates", LangOpts.CPlusPlus0x)
.Case("cxx_attributes", LangOpts.CPlusPlus0x)
.Case("cxx_auto_type", LangOpts.CPlusPlus0x)
.Case("cxx_decltype", LangOpts.CPlusPlus0x)
@@ -566,7 +571,7 @@ static bool HasFeature(const Preprocessor &PP, const IdentifierInfo *II) {
.Case("cxx_inline_namespaces", LangOpts.CPlusPlus0x)
//.Case("cxx_lambdas", false)
.Case("cxx_noexcept", LangOpts.CPlusPlus0x)
- //.Case("cxx_nullptr", false)
+ .Case("cxx_nullptr", LangOpts.CPlusPlus0x)
.Case("cxx_override_control", LangOpts.CPlusPlus0x)
.Case("cxx_range_for", LangOpts.CPlusPlus0x)
.Case("cxx_reference_qualified_functions", LangOpts.CPlusPlus0x)
@@ -591,14 +596,45 @@ static bool HasFeature(const Preprocessor &PP, const IdentifierInfo *II) {
.Case("is_empty", LangOpts.CPlusPlus)
.Case("is_enum", LangOpts.CPlusPlus)
.Case("is_literal", LangOpts.CPlusPlus)
+ .Case("is_standard_layout", LangOpts.CPlusPlus)
.Case("is_pod", LangOpts.CPlusPlus)
.Case("is_polymorphic", LangOpts.CPlusPlus)
.Case("is_trivial", LangOpts.CPlusPlus)
+ .Case("is_trivially_copyable", LangOpts.CPlusPlus)
.Case("is_union", LangOpts.CPlusPlus)
.Case("tls", PP.getTargetInfo().isTLSSupported())
.Default(false);
}
+/// HasExtension - Return true if we recognize and implement the feature
+/// specified by the identifier, either as an extension or a standard language
+/// feature.
+static bool HasExtension(const Preprocessor &PP, const IdentifierInfo *II) {
+ if (HasFeature(PP, II))
+ return true;
+
+ // If the use of an extension results in an error diagnostic, extensions are
+ // effectively unavailable, so just return false here.
+ if (PP.getDiagnostics().getExtensionHandlingBehavior()==Diagnostic::Ext_Error)
+ return false;
+
+ const LangOptions &LangOpts = PP.getLangOptions();
+
+ // Because we inherit the feature list from HasFeature, this string switch
+ // must be less restrictive than HasFeature's.
+ return llvm::StringSwitch<bool>(II->getName())
+ // C1X features supported by other languages as extensions.
+ .Case("c_generic_selections", true)
+ .Case("c_static_assert", true)
+ // C++0x features supported by other languages as extensions.
+ .Case("cxx_deleted_functions", LangOpts.CPlusPlus)
+ .Case("cxx_inline_namespaces", LangOpts.CPlusPlus)
+ .Case("cxx_override_control", LangOpts.CPlusPlus)
+ .Case("cxx_reference_qualified_functions", LangOpts.CPlusPlus)
+ .Case("cxx_rvalue_references", LangOpts.CPlusPlus)
+ .Default(false);
+}
+
/// HasAttribute - Return true if we recognize and implement the attribute
/// specified by the given identifier.
static bool HasAttribute(const IdentifierInfo *II) {
@@ -847,10 +883,11 @@ void Preprocessor::ExpandBuiltinMacro(Token &Tok) {
// __COUNTER__ expands to a simple numeric value.
OS << CounterValue++;
Tok.setKind(tok::numeric_constant);
- } else if (II == Ident__has_feature ||
- II == Ident__has_builtin ||
+ } else if (II == Ident__has_feature ||
+ II == Ident__has_extension ||
+ II == Ident__has_builtin ||
II == Ident__has_attribute) {
- // The argument to these two builtins should be a parenthesized identifier.
+ // The argument to these builtins should be a parenthesized identifier.
SourceLocation StartLoc = Tok.getLocation();
bool IsValid = false;
@@ -879,6 +916,8 @@ void Preprocessor::ExpandBuiltinMacro(Token &Tok) {
Value = FeatureII->getBuiltinID() != 0;
} else if (II == Ident__has_attribute)
Value = HasAttribute(FeatureII);
+ else if (II == Ident__has_extension)
+ Value = HasExtension(*this, FeatureII);
else {
assert(II == Ident__has_feature && "Must be feature check");
Value = HasFeature(*this, FeatureII);
diff --git a/lib/Lex/Pragma.cpp b/lib/Lex/Pragma.cpp
index 0c18091..23855d4 100644
--- a/lib/Lex/Pragma.cpp
+++ b/lib/Lex/Pragma.cpp
@@ -330,16 +330,16 @@ void Preprocessor::HandlePragmaSystemHeader(Token &SysHeaderTok) {
unsigned FilenameID = SourceMgr.getLineTableFilenameID(PLoc.getFilename(),
FilenameLen);
+ // Notify the client, if desired, that we are in a new source file.
+ if (Callbacks)
+ Callbacks->FileChanged(SysHeaderTok.getLocation(),
+ PPCallbacks::SystemHeaderPragma, SrcMgr::C_System);
+
// Emit a line marker. This will change any source locations from this point
// forward to realize they are in a system header.
// Create a line note with this information.
SourceMgr.AddLineNote(SysHeaderTok.getLocation(), PLoc.getLine(), FilenameID,
false, false, true, false);
-
- // Notify the client, if desired, that we are in a new source file.
- if (Callbacks)
- Callbacks->FileChanged(SysHeaderTok.getLocation(),
- PPCallbacks::SystemHeaderPragma, SrcMgr::C_System);
}
/// HandlePragmaDependency - Handle #pragma GCC dependency "foo" blah.
@@ -824,9 +824,17 @@ struct PragmaDebugHandler : public PragmaHandler {
}
}
+// Disable MSVC warning about runtime stack overflow.
+#ifdef _MSC_VER
+ #pragma warning(disable : 4717)
+#endif
void DebugOverflowStack() {
DebugOverflowStack();
}
+#ifdef _MSC_VER
+ #pragma warning(default : 4717)
+#endif
+
};
/// PragmaDiagnosticHandler - e.g. '#pragma GCC diagnostic ignored "-Wformat"'
@@ -898,8 +906,7 @@ public:
return;
}
- std::string WarningName(Literal.GetString(),
- Literal.GetString()+Literal.GetStringLength());
+ llvm::StringRef WarningName(Literal.GetString(), Literal.GetStringLength());
if (WarningName.size() < 3 || WarningName[0] != '-' ||
WarningName[1] != 'W') {
@@ -908,7 +915,7 @@ public:
return;
}
- if (PP.getDiagnostics().setDiagnosticGroupMapping(WarningName.c_str()+2,
+ if (PP.getDiagnostics().setDiagnosticGroupMapping(WarningName.substr(2),
Map, DiagLoc))
PP.Diag(StrToks[0].getLocation(),
diag::warn_pragma_diagnostic_unknown_warning) << WarningName;
diff --git a/lib/Lex/PreprocessingRecord.cpp b/lib/Lex/PreprocessingRecord.cpp
index 9555611..0c8d948 100644
--- a/lib/Lex/PreprocessingRecord.cpp
+++ b/lib/Lex/PreprocessingRecord.cpp
@@ -45,8 +45,9 @@ void PreprocessingRecord::MaybeLoadPreallocatedEntities() const {
ExternalSource->ReadPreprocessedEntities();
}
-PreprocessingRecord::PreprocessingRecord()
- : ExternalSource(0), NumPreallocatedEntities(0),
+PreprocessingRecord::PreprocessingRecord(bool IncludeNestedMacroInstantiations)
+ : IncludeNestedMacroInstantiations(IncludeNestedMacroInstantiations),
+ ExternalSource(0), NumPreallocatedEntities(0),
LoadedPreallocatedEntities(false)
{
}
@@ -120,6 +121,9 @@ MacroDefinition *PreprocessingRecord::findMacroDefinition(const MacroInfo *MI) {
}
void PreprocessingRecord::MacroExpands(const Token &Id, const MacroInfo* MI) {
+ if (!IncludeNestedMacroInstantiations && Id.getLocation().isMacroID())
+ return;
+
if (MacroDefinition *Def = findMacroDefinition(MI))
PreprocessedEntities.push_back(
new (*this) MacroInstantiation(Id.getIdentifierInfo(),
diff --git a/lib/Lex/Preprocessor.cpp b/lib/Lex/Preprocessor.cpp
index 31fd667..fdc18f8 100644
--- a/lib/Lex/Preprocessor.cpp
+++ b/lib/Lex/Preprocessor.cpp
@@ -527,10 +527,11 @@ CommentHandler::~CommentHandler() { }
CodeCompletionHandler::~CodeCompletionHandler() { }
-void Preprocessor::createPreprocessingRecord() {
+void Preprocessor::createPreprocessingRecord(
+ bool IncludeNestedMacroInstantiations) {
if (Record)
return;
- Record = new PreprocessingRecord;
+ Record = new PreprocessingRecord(IncludeNestedMacroInstantiations);
addPPCallbacks(Record);
}
diff --git a/lib/Makefile b/lib/Makefile
index eda7017..924819c 100755
--- a/lib/Makefile
+++ b/lib/Makefile
@@ -10,7 +10,7 @@ CLANG_LEVEL := ..
PARALLEL_DIRS = Headers Basic Lex Parse AST Sema CodeGen Analysis \
StaticAnalyzer Rewrite Serialization Frontend FrontendTool \
- Index Driver Tooling
+ Index Driver
include $(CLANG_LEVEL)/Makefile
diff --git a/lib/Parse/ParseCXXInlineMethods.cpp b/lib/Parse/ParseCXXInlineMethods.cpp
index 87e2f34..f5c6998 100644
--- a/lib/Parse/ParseCXXInlineMethods.cpp
+++ b/lib/Parse/ParseCXXInlineMethods.cpp
@@ -23,10 +23,11 @@ using namespace clang;
/// and store its tokens for parsing after the C++ class is complete.
Decl *Parser::ParseCXXInlineMethodDef(AccessSpecifier AS, ParsingDeclarator &D,
const ParsedTemplateInfo &TemplateInfo,
- const VirtSpecifiers& VS) {
+ const VirtSpecifiers& VS, ExprResult& Init) {
assert(D.isFunctionDeclarator() && "This isn't a function declarator!");
- assert((Tok.is(tok::l_brace) || Tok.is(tok::colon) || Tok.is(tok::kw_try)) &&
- "Current token not a '{', ':' or 'try'!");
+ assert((Tok.is(tok::l_brace) || Tok.is(tok::colon) || Tok.is(tok::kw_try) ||
+ Tok.is(tok::equal)) &&
+ "Current token not a '{', ':', '=', or 'try'!");
MultiTemplateParamsArg TemplateParams(Actions,
TemplateInfo.TemplateParams ? TemplateInfo.TemplateParams->data() : 0,
@@ -40,13 +41,49 @@ Decl *Parser::ParseCXXInlineMethodDef(AccessSpecifier AS, ParsingDeclarator &D,
else { // FIXME: pass template information through
FnD = Actions.ActOnCXXMemberDeclarator(getCurScope(), AS, D,
move(TemplateParams), 0,
- VS, 0, /*IsDefinition*/true);
+ VS, Init.release(),
+ /*HasInit=*/false,
+ /*IsDefinition*/true);
}
HandleMemberFunctionDefaultArgs(D, FnD);
D.complete(FnD);
+ if (Tok.is(tok::equal)) {
+ ConsumeToken();
+
+ bool Delete = false;
+ SourceLocation KWLoc;
+ if (Tok.is(tok::kw_delete)) {
+ if (!getLang().CPlusPlus0x)
+ Diag(Tok, diag::warn_deleted_function_accepted_as_extension);
+
+ KWLoc = ConsumeToken();
+ Actions.SetDeclDeleted(FnD, KWLoc);
+ Delete = true;
+ } else if (Tok.is(tok::kw_default)) {
+ if (!getLang().CPlusPlus0x)
+ Diag(Tok, diag::warn_defaulted_function_accepted_as_extension);
+
+ KWLoc = ConsumeToken();
+ Actions.SetDeclDefaulted(FnD, KWLoc);
+ } else {
+ llvm_unreachable("function definition after = not 'delete' or 'default'");
+ }
+
+ if (Tok.is(tok::comma)) {
+ Diag(KWLoc, diag::err_default_delete_in_multiple_declaration)
+ << Delete;
+ SkipUntil(tok::semi);
+ } else {
+ ExpectAndConsume(tok::semi, diag::err_expected_semi_after,
+ Delete ? "delete" : "default", tok::semi);
+ }
+
+ return FnD;
+ }
+
// In delayed template parsing mode, if we are within a class template
// or if we are about to parse function member template then consume
// the tokens and store them for parsing at the end of the translation unit.
@@ -130,8 +167,50 @@ Decl *Parser::ParseCXXInlineMethodDef(AccessSpecifier AS, ParsingDeclarator &D,
return FnD;
}
+/// ParseCXXNonStaticMemberInitializer - We parsed and verified that the
+/// specified Declarator is a well formed C++ non-static data member
+/// declaration. Now lex its initializer and store its tokens for parsing
+/// after the class is complete.
+void Parser::ParseCXXNonStaticMemberInitializer(Decl *VarD) {
+ assert((Tok.is(tok::l_brace) || Tok.is(tok::equal)) &&
+ "Current token not a '{' or '='!");
+
+ LateParsedMemberInitializer *MI =
+ new LateParsedMemberInitializer(this, VarD);
+ getCurrentClass().LateParsedDeclarations.push_back(MI);
+ CachedTokens &Toks = MI->Toks;
+
+ tok::TokenKind kind = Tok.getKind();
+ if (kind == tok::equal) {
+ Toks.push_back(Tok);
+ ConsumeAnyToken();
+ }
+
+ if (kind == tok::l_brace) {
+ // Begin by storing the '{' token.
+ Toks.push_back(Tok);
+ ConsumeBrace();
+
+ // Consume everything up to (and including) the matching right brace.
+ ConsumeAndStoreUntil(tok::r_brace, Toks, /*StopAtSemi=*/true);
+ } else {
+ // Consume everything up to (but excluding) the comma or semicolon.
+ ConsumeAndStoreUntil(tok::comma, Toks, /*StopAtSemi=*/true,
+ /*ConsumeFinalToken=*/false);
+ }
+
+ // Store an artificial EOF token to ensure that we don't run off the end of
+ // the initializer when we come to parse it.
+ Token Eof;
+ Eof.startToken();
+ Eof.setKind(tok::eof);
+ Eof.setLocation(Tok.getLocation());
+ Toks.push_back(Eof);
+}
+
Parser::LateParsedDeclaration::~LateParsedDeclaration() {}
void Parser::LateParsedDeclaration::ParseLexedMethodDeclarations() {}
+void Parser::LateParsedDeclaration::ParseLexedMemberInitializers() {}
void Parser::LateParsedDeclaration::ParseLexedMethodDefs() {}
Parser::LateParsedClass::LateParsedClass(Parser *P, ParsingClass *C)
@@ -145,6 +224,10 @@ void Parser::LateParsedClass::ParseLexedMethodDeclarations() {
Self->ParseLexedMethodDeclarations(*Class);
}
+void Parser::LateParsedClass::ParseLexedMemberInitializers() {
+ Self->ParseLexedMemberInitializers(*Class);
+}
+
void Parser::LateParsedClass::ParseLexedMethodDefs() {
Self->ParseLexedMethodDefs(*Class);
}
@@ -157,6 +240,10 @@ void Parser::LexedMethod::ParseLexedMethodDefs() {
Self->ParseLexedMethodDef(*this);
}
+void Parser::LateParsedMemberInitializer::ParseLexedMemberInitializers() {
+ Self->ParseLexedMemberInitializer(*this);
+}
+
/// ParseLexedMethodDeclarations - We finished parsing the member
/// specification of a top (non-nested) C++ class. Now go over the
/// stack of method declarations with some parts for which parsing was
@@ -328,8 +415,70 @@ void Parser::ParseLexedMethodDef(LexedMethod &LM) {
origLoc))
while (Tok.getLocation() != origLoc && Tok.isNot(tok::eof))
ConsumeAnyToken();
+ }
+}
+
+/// ParseLexedMemberInitializers - We finished parsing the member specification
+/// of a top (non-nested) C++ class. Now go over the stack of lexed data member
+/// initializers that were collected during its parsing and parse them all.
+void Parser::ParseLexedMemberInitializers(ParsingClass &Class) {
+ bool HasTemplateScope = !Class.TopLevelClass && Class.TemplateScope;
+ ParseScope ClassTemplateScope(this, Scope::TemplateParamScope,
+ HasTemplateScope);
+ if (HasTemplateScope)
+ Actions.ActOnReenterTemplateScope(getCurScope(), Class.TagOrTemplate);
+ // Set or update the scope flags to include Scope::ThisScope.
+ bool AlreadyHasClassScope = Class.TopLevelClass;
+ unsigned ScopeFlags = Scope::ClassScope|Scope::DeclScope|Scope::ThisScope;
+ ParseScope ClassScope(this, ScopeFlags, !AlreadyHasClassScope);
+ ParseScopeFlags ClassScopeFlags(this, ScopeFlags, AlreadyHasClassScope);
+
+ if (!AlreadyHasClassScope)
+ Actions.ActOnStartDelayedMemberDeclarations(getCurScope(),
+ Class.TagOrTemplate);
+
+ for (size_t i = 0; i < Class.LateParsedDeclarations.size(); ++i) {
+ Class.LateParsedDeclarations[i]->ParseLexedMemberInitializers();
}
+
+ if (!AlreadyHasClassScope)
+ Actions.ActOnFinishDelayedMemberDeclarations(getCurScope(),
+ Class.TagOrTemplate);
+
+ Actions.ActOnFinishDelayedMemberInitializers(Class.TagOrTemplate);
+}
+
+void Parser::ParseLexedMemberInitializer(LateParsedMemberInitializer &MI) {
+ if (MI.Field->isInvalidDecl())
+ return;
+
+ // Append the current token at the end of the new token stream so that it
+ // doesn't get lost.
+ MI.Toks.push_back(Tok);
+ PP.EnterTokenStream(MI.Toks.data(), MI.Toks.size(), true, false);
+
+ // Consume the previously pushed token.
+ ConsumeAnyToken();
+
+ SourceLocation EqualLoc;
+ ExprResult Init = ParseCXXMemberInitializer(/*IsFunction=*/false, EqualLoc);
+
+ Actions.ActOnCXXInClassMemberInitializer(MI.Field, EqualLoc, Init.release());
+
+ // The next token should be our artificial terminating EOF token.
+ if (Tok.isNot(tok::eof)) {
+ SourceLocation EndLoc = PP.getLocForEndOfToken(PrevTokLocation);
+ if (!EndLoc.isValid())
+ EndLoc = Tok.getLocation();
+ // No fixit; we can't recover as if there were a semicolon here.
+ Diag(EndLoc, diag::err_expected_semi_decl_list);
+
+ // Consume tokens until we hit the artificial EOF.
+ while (Tok.isNot(tok::eof))
+ ConsumeAnyToken();
+ }
+ ConsumeAnyToken();
}
/// ConsumeAndStoreUntil - Consume and store the token at the passed token
diff --git a/lib/Parse/ParseDecl.cpp b/lib/Parse/ParseDecl.cpp
index a20e90b..ad3fcfe 100644
--- a/lib/Parse/ParseDecl.cpp
+++ b/lib/Parse/ParseDecl.cpp
@@ -253,9 +253,17 @@ void Parser::ParseMicrosoftDeclSpec(ParsedAttributes &attrs) {
SkipUntil(tok::r_paren, true); // skip until ) or ;
return;
}
+
while (Tok.getIdentifierInfo()) {
IdentifierInfo *AttrName = Tok.getIdentifierInfo();
SourceLocation AttrNameLoc = ConsumeToken();
+
+ // FIXME: Remove this when we have proper __declspec(property()) support.
+ // Just skip everything inside property().
+ if (AttrName->getName() == "property") {
+ ConsumeParen();
+ SkipUntil(tok::r_paren);
+ }
if (Tok.is(tok::l_paren)) {
ConsumeParen();
// FIXME: This doesn't parse __declspec(property(get=get_func_name))
@@ -806,8 +814,10 @@ Parser::DeclGroupPtrTy Parser::ParseDeclGroup(ParsingDeclSpec &DS,
// analyzed.
if (FRI && Tok.is(tok::colon)) {
FRI->ColonLoc = ConsumeToken();
- // FIXME: handle braced-init-list here.
- FRI->RangeExpr = ParseExpression();
+ if (Tok.is(tok::l_brace))
+ FRI->RangeExpr = ParseBraceInitializer();
+ else
+ FRI->RangeExpr = ParseExpression();
Decl *ThisDecl = Actions.ActOnDeclarator(getCurScope(), D);
Actions.ActOnCXXForRangeDecl(ThisDecl);
Actions.FinalizeDeclaration(ThisDecl);
@@ -906,6 +916,7 @@ bool Parser::ParseAttributesAfterDeclarator(Declarator &D) {
/// [C++] '(' expression-list ')'
/// [C++0x] '=' 'default' [TODO]
/// [C++0x] '=' 'delete'
+/// [C++0x] braced-init-list
///
/// According to the standard grammar, =default and =delete are function
/// definitions, but that definitely doesn't fit with the parser here.
@@ -960,12 +971,17 @@ Decl *Parser::ParseDeclarationAfterDeclaratorAndAttributes(Declarator &D,
diag::err_invalid_equalequal_after_declarator)) {
ConsumeToken();
if (Tok.is(tok::kw_delete)) {
- SourceLocation DelLoc = ConsumeToken();
-
- if (!getLang().CPlusPlus0x)
- Diag(DelLoc, diag::warn_deleted_function_accepted_as_extension);
-
- Actions.SetDeclDeleted(ThisDecl, DelLoc);
+ if (D.isFunctionDeclarator())
+ Diag(ConsumeToken(), diag::err_default_delete_in_multiple_declaration)
+ << 1 /* delete */;
+ else
+ Diag(ConsumeToken(), diag::err_deleted_non_function);
+ } else if (Tok.is(tok::kw_default)) {
+ if (D.isFunctionDeclarator())
+ Diag(Tok, diag::err_default_delete_in_multiple_declaration)
+ << 1 /* delete */;
+ else
+ Diag(ConsumeToken(), diag::err_default_special_members);
} else {
if (getLang().CPlusPlus && D.getCXXScopeSpec().isSet()) {
EnterScope(0);
@@ -1028,6 +1044,26 @@ Decl *Parser::ParseDeclarationAfterDeclaratorAndAttributes(Declarator &D,
RParenLoc,
TypeContainsAuto);
}
+ } else if (getLang().CPlusPlus0x && Tok.is(tok::l_brace)) {
+ // Parse C++0x braced-init-list.
+ if (D.getCXXScopeSpec().isSet()) {
+ EnterScope(0);
+ Actions.ActOnCXXEnterDeclInitializer(getCurScope(), ThisDecl);
+ }
+
+ ExprResult Init(ParseBraceInitializer());
+
+ if (D.getCXXScopeSpec().isSet()) {
+ Actions.ActOnCXXExitDeclInitializer(getCurScope(), ThisDecl);
+ ExitScope();
+ }
+
+ if (Init.isInvalid()) {
+ Actions.ActOnInitializerError(ThisDecl);
+ } else
+ Actions.AddInitializerToDecl(ThisDecl, Init.take(),
+ /*DirectInit=*/true, TypeContainsAuto);
+
} else {
Actions.ActOnUninitializedDecl(ThisDecl, TypeContainsAuto);
}
@@ -1846,6 +1882,9 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS,
ParseDecltypeSpecifier(DS);
continue;
+ case tok::kw___underlying_type:
+ ParseUnderlyingTypeSpecifier(DS);
+
// OpenCL qualifiers:
case tok::kw_private:
if (!getLang().OpenCL)
@@ -2116,6 +2155,11 @@ bool Parser::ParseOptionalTypeSpecifier(DeclSpec &DS, bool& isInvalid,
ParseDecltypeSpecifier(DS);
return true;
+ // C++0x type traits support.
+ case tok::kw___underlying_type:
+ ParseUnderlyingTypeSpecifier(DS);
+ return true;
+
// OpenCL qualifiers:
case tok::kw_private:
if (!getLang().OpenCL)
diff --git a/lib/Parse/ParseDeclCXX.cpp b/lib/Parse/ParseDeclCXX.cpp
index 8c0aa1b..51aa010 100644
--- a/lib/Parse/ParseDeclCXX.cpp
+++ b/lib/Parse/ParseDeclCXX.cpp
@@ -60,12 +60,20 @@ Decl *Parser::ParseNamespace(unsigned Context,
SourceLocation IdentLoc;
IdentifierInfo *Ident = 0;
+ std::vector<SourceLocation> ExtraIdentLoc;
+ std::vector<IdentifierInfo*> ExtraIdent;
+ std::vector<SourceLocation> ExtraNamespaceLoc;
Token attrTok;
if (Tok.is(tok::identifier)) {
Ident = Tok.getIdentifierInfo();
IdentLoc = ConsumeToken(); // eat the identifier.
+ while (Tok.is(tok::coloncolon) && NextToken().is(tok::identifier)) {
+ ExtraNamespaceLoc.push_back(ConsumeToken());
+ ExtraIdent.push_back(Tok.getIdentifierInfo());
+ ExtraIdentLoc.push_back(ConsumeToken());
+ }
}
// Read label attributes, if present.
@@ -85,7 +93,12 @@ Decl *Parser::ParseNamespace(unsigned Context,
return ParseNamespaceAlias(NamespaceLoc, IdentLoc, Ident, DeclEnd);
}
+
if (Tok.isNot(tok::l_brace)) {
+ if (!ExtraIdent.empty()) {
+ Diag(ExtraNamespaceLoc[0], diag::err_nested_namespaces_with_double_colon)
+ << SourceRange(ExtraNamespaceLoc.front(), ExtraIdentLoc.back());
+ }
Diag(Tok, Ident ? diag::err_expected_lbrace :
diag::err_expected_ident_lbrace);
return 0;
@@ -96,11 +109,44 @@ Decl *Parser::ParseNamespace(unsigned Context,
if (getCurScope()->isClassScope() || getCurScope()->isTemplateParamScope() ||
getCurScope()->isInObjcMethodScope() || getCurScope()->getBlockParent() ||
getCurScope()->getFnParent()) {
+ if (!ExtraIdent.empty()) {
+ Diag(ExtraNamespaceLoc[0], diag::err_nested_namespaces_with_double_colon)
+ << SourceRange(ExtraNamespaceLoc.front(), ExtraIdentLoc.back());
+ }
Diag(LBrace, diag::err_namespace_nonnamespace_scope);
SkipUntil(tok::r_brace, false);
return 0;
}
+ if (!ExtraIdent.empty()) {
+ TentativeParsingAction TPA(*this);
+ SkipUntil(tok::r_brace, /*StopAtSemi*/false, /*DontConsume*/true);
+ Token rBraceToken = Tok;
+ TPA.Revert();
+
+ if (!rBraceToken.is(tok::r_brace)) {
+ Diag(ExtraNamespaceLoc[0], diag::err_nested_namespaces_with_double_colon)
+ << SourceRange(ExtraNamespaceLoc.front(), ExtraIdentLoc.back());
+ } else {
+ std::string NamespaceFix;
+ for (std::vector<IdentifierInfo*>::iterator I = ExtraIdent.begin(),
+ E = ExtraIdent.end(); I != E; ++I) {
+ NamespaceFix += " { namespace ";
+ NamespaceFix += (*I)->getName();
+ }
+
+ std::string RBraces;
+ for (unsigned i = 0, e = ExtraIdent.size(); i != e; ++i)
+ RBraces += "} ";
+
+ Diag(ExtraNamespaceLoc[0], diag::err_nested_namespaces_with_double_colon)
+ << FixItHint::CreateReplacement(SourceRange(ExtraNamespaceLoc.front(),
+ ExtraIdentLoc.back()),
+ NamespaceFix)
+ << FixItHint::CreateInsertion(rBraceToken.getLocation(), RBraces);
+ }
+ }
+
// If we're still good, complain about inline namespaces in non-C++0x now.
if (!getLang().CPlusPlus0x && InlineLoc.isValid())
Diag(InlineLoc, diag::ext_inline_namespace);
@@ -115,23 +161,56 @@ Decl *Parser::ParseNamespace(unsigned Context,
PrettyDeclStackTraceEntry CrashInfo(Actions, NamespcDecl, NamespaceLoc,
"parsing namespace");
- while (Tok.isNot(tok::r_brace) && Tok.isNot(tok::eof)) {
- ParsedAttributesWithRange attrs(AttrFactory);
- MaybeParseCXX0XAttributes(attrs);
- MaybeParseMicrosoftAttributes(attrs);
- ParseExternalDeclaration(attrs);
- }
+ SourceLocation RBraceLoc;
+ // Parse the contents of the namespace. This includes parsing recovery on
+ // any improperly nested namespaces.
+ ParseInnerNamespace(ExtraIdentLoc, ExtraIdent, ExtraNamespaceLoc, 0,
+ InlineLoc, LBrace, attrs, RBraceLoc);
// Leave the namespace scope.
NamespaceScope.Exit();
- SourceLocation RBraceLoc = MatchRHSPunctuation(tok::r_brace, LBrace);
Actions.ActOnFinishNamespaceDef(NamespcDecl, RBraceLoc);
DeclEnd = RBraceLoc;
return NamespcDecl;
}
+/// ParseInnerNamespace - Parse the contents of a namespace.
+void Parser::ParseInnerNamespace(std::vector<SourceLocation>& IdentLoc,
+ std::vector<IdentifierInfo*>& Ident,
+ std::vector<SourceLocation>& NamespaceLoc,
+ unsigned int index, SourceLocation& InlineLoc,
+ SourceLocation& LBrace,
+ ParsedAttributes& attrs,
+ SourceLocation& RBraceLoc) {
+ if (index == Ident.size()) {
+ while (Tok.isNot(tok::r_brace) && Tok.isNot(tok::eof)) {
+ ParsedAttributesWithRange attrs(AttrFactory);
+ MaybeParseCXX0XAttributes(attrs);
+ MaybeParseMicrosoftAttributes(attrs);
+ ParseExternalDeclaration(attrs);
+ }
+ RBraceLoc = MatchRHSPunctuation(tok::r_brace, LBrace);
+
+ return;
+ }
+
+ // Parse improperly nested namespaces.
+ ParseScope NamespaceScope(this, Scope::DeclScope);
+ Decl *NamespcDecl =
+ Actions.ActOnStartNamespaceDef(getCurScope(), SourceLocation(),
+ NamespaceLoc[index], IdentLoc[index],
+ Ident[index], LBrace, attrs.getList());
+
+ ParseInnerNamespace(IdentLoc, Ident, NamespaceLoc, ++index, InlineLoc,
+ LBrace, attrs, RBraceLoc);
+
+ NamespaceScope.Exit();
+
+ Actions.ActOnFinishNamespaceDef(NamespcDecl, RBraceLoc);
+}
+
/// ParseNamespaceAlias - Parse the part after the '=' in a namespace
/// alias definition.
///
@@ -387,13 +466,35 @@ Decl *Parser::ParseUsingDeclaration(unsigned Context,
bool IsAliasDecl = Tok.is(tok::equal);
TypeResult TypeAlias;
if (IsAliasDecl) {
- // TODO: Do we want to support attributes somewhere in an alias declaration?
- // Can't follow GCC since it doesn't support them yet!
+ // TODO: Attribute support. C++0x attributes may appear before the equals.
+ // Where can GNU attributes appear?
ConsumeToken();
if (!getLang().CPlusPlus0x)
Diag(Tok.getLocation(), diag::ext_alias_declaration);
+ // Type alias templates cannot be specialized.
+ int SpecKind = -1;
+ if (TemplateInfo.Kind == ParsedTemplateInfo::Template &&
+ Name.getKind() == UnqualifiedId::IK_TemplateId)
+ SpecKind = 0;
+ if (TemplateInfo.Kind == ParsedTemplateInfo::ExplicitSpecialization)
+ SpecKind = 1;
+ if (TemplateInfo.Kind == ParsedTemplateInfo::ExplicitInstantiation)
+ SpecKind = 2;
+ if (SpecKind != -1) {
+ SourceRange Range;
+ if (SpecKind == 0)
+ Range = SourceRange(Name.TemplateId->LAngleLoc,
+ Name.TemplateId->RAngleLoc);
+ else
+ Range = TemplateInfo.getSourceRange();
+ Diag(Range.getBegin(), diag::err_alias_declaration_specialization)
+ << SpecKind << Range;
+ SkipUntil(tok::semi);
+ return 0;
+ }
+
// Name must be an identifier.
if (Name.getKind() != UnqualifiedId::IK_Identifier) {
Diag(Name.StartLocation, diag::err_alias_declaration_not_identifier);
@@ -408,7 +509,9 @@ Decl *Parser::ParseUsingDeclaration(unsigned Context,
Diag(SS.getBeginLoc(), diag::err_alias_declaration_not_identifier)
<< FixItHint::CreateRemoval(SS.getRange());
- TypeAlias = ParseTypeName(0, Declarator::AliasDeclContext);
+ TypeAlias = ParseTypeName(0, TemplateInfo.Kind ?
+ Declarator::AliasTemplateContext :
+ Declarator::AliasDeclContext);
} else
// Parse (optional) attributes (most likely GNU strong-using extension).
MaybeParseGNUAttributes(attrs);
@@ -421,9 +524,9 @@ Decl *Parser::ParseUsingDeclaration(unsigned Context,
tok::semi);
// Diagnose an attempt to declare a templated using-declaration.
- // TODO: in C++0x, alias-declarations can be templates:
+ // In C++0x, alias-declarations can be templates:
// template <...> using id = type;
- if (TemplateInfo.Kind) {
+ if (TemplateInfo.Kind && !IsAliasDecl) {
SourceRange R = TemplateInfo.getSourceRange();
Diag(UsingLoc, diag::err_templated_using_declaration)
<< R << FixItHint::CreateRemoval(R);
@@ -434,9 +537,14 @@ Decl *Parser::ParseUsingDeclaration(unsigned Context,
return 0;
}
- if (IsAliasDecl)
- return Actions.ActOnAliasDeclaration(getCurScope(), AS, UsingLoc, Name,
- TypeAlias);
+ if (IsAliasDecl) {
+ TemplateParameterLists *TemplateParams = TemplateInfo.TemplateParams;
+ MultiTemplateParamsArg TemplateParamsArg(Actions,
+ TemplateParams ? TemplateParams->data() : 0,
+ TemplateParams ? TemplateParams->size() : 0);
+ return Actions.ActOnAliasDeclaration(getCurScope(), AS, TemplateParamsArg,
+ UsingLoc, Name, TypeAlias);
+ }
return Actions.ActOnUsingDeclaration(getCurScope(), AS, true, UsingLoc, SS,
Name, attrs.getList(),
@@ -543,6 +651,42 @@ void Parser::ParseDecltypeSpecifier(DeclSpec &DS) {
Diag(StartLoc, DiagID) << PrevSpec;
}
+void Parser::ParseUnderlyingTypeSpecifier(DeclSpec &DS) {
+ assert(Tok.is(tok::kw___underlying_type) &&
+ "Not an underlying type specifier");
+
+ SourceLocation StartLoc = ConsumeToken();
+ SourceLocation LParenLoc = Tok.getLocation();
+
+ if (ExpectAndConsume(tok::l_paren, diag::err_expected_lparen_after,
+ "__underlying_type")) {
+ SkipUntil(tok::r_paren);
+ return;
+ }
+
+ TypeResult Result = ParseTypeName();
+ if (Result.isInvalid()) {
+ SkipUntil(tok::r_paren);
+ return;
+ }
+
+ // Match the ')'
+ SourceLocation RParenLoc;
+ if (Tok.is(tok::r_paren))
+ RParenLoc = ConsumeParen();
+ else
+ MatchRHSPunctuation(tok::r_paren, LParenLoc);
+
+ if (RParenLoc.isInvalid())
+ return;
+
+ const char *PrevSpec = 0;
+ unsigned DiagID;
+ if (DS.SetTypeSpecType(DeclSpec::TST_underlyingType, StartLoc, PrevSpec,
+ DiagID, Result.release()))
+ Diag(StartLoc, DiagID) << PrevSpec;
+}
+
/// ParseClassName - Parse a C++ class-name, which names a class. Note
/// that we only check that the result names a type; semantic analysis
/// will need to verify that the type names a class. The result is
@@ -1409,6 +1553,7 @@ bool Parser::isCXX0XFinalKeyword() const {
/// member-declarator:
/// declarator virt-specifier-seq[opt] pure-specifier[opt]
/// declarator constant-initializer[opt]
+/// [C++11] declarator brace-or-equal-initializer[opt]
/// identifier[opt] ':' constant-expression
///
/// virt-specifier-seq:
@@ -1515,8 +1660,6 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS,
MaybeParseMicrosoftAttributes(attrs);
if (Tok.is(tok::kw_using)) {
- // FIXME: Check for template aliases
-
ProhibitAttributes(attrs);
// Eat 'using'.
@@ -1527,7 +1670,7 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS,
SkipUntil(tok::semi, true, true);
} else {
SourceLocation DeclEnd;
- // Otherwise, it must be using-declaration.
+ // Otherwise, it must be a using-declaration or an alias-declaration.
ParseUsingDeclaration(Declarator::MemberContext, TemplateInfo,
UsingLoc, DeclEnd, AS);
}
@@ -1547,13 +1690,14 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS,
if (Tok.is(tok::semi)) {
ConsumeToken();
Decl *TheDecl =
- Actions.ParsedFreeStandingDeclSpec(getCurScope(), AS, DS);
+ Actions.ParsedFreeStandingDeclSpec(getCurScope(), AS, DS, TemplateParams);
DS.complete(TheDecl);
return;
}
ParsingDeclarator DeclaratorInfo(*this, DS, Declarator::MemberContext);
VirtSpecifiers VS;
+ ExprResult Init;
if (Tok.isNot(tok::colon)) {
// Don't parse FOO:BAR as if it were a typo for FOO::BAR.
@@ -1575,10 +1719,36 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS,
// If attributes exist after the declarator, but before an '{', parse them.
MaybeParseGNUAttributes(DeclaratorInfo);
+ // MSVC permits pure specifier on inline functions declared at class scope.
+ // Hence check for =0 before checking for function definition.
+ if (getLang().Microsoft && Tok.is(tok::equal) &&
+ DeclaratorInfo.isFunctionDeclarator() &&
+ NextToken().is(tok::numeric_constant)) {
+ ConsumeToken();
+ Init = ParseInitializer();
+ if (Init.isInvalid())
+ SkipUntil(tok::comma, true, true);
+ }
+
+ bool IsDefinition = false;
// function-definition:
- if (Tok.is(tok::l_brace)
- || (DeclaratorInfo.isFunctionDeclarator() &&
- (Tok.is(tok::colon) || Tok.is(tok::kw_try)))) {
+ //
+ // In C++11, a non-function declarator followed by an open brace is a
+ // braced-init-list for an in-class member initialization, not an
+ // erroneous function definition.
+ if (Tok.is(tok::l_brace) && !getLang().CPlusPlus0x) {
+ IsDefinition = true;
+ } else if (DeclaratorInfo.isFunctionDeclarator()) {
+ if (Tok.is(tok::l_brace) || Tok.is(tok::colon) || Tok.is(tok::kw_try)) {
+ IsDefinition = true;
+ } else if (Tok.is(tok::equal)) {
+ const Token &KW = NextToken();
+ if (KW.is(tok::kw_default) || KW.is(tok::kw_delete))
+ IsDefinition = true;
+ }
+ }
+
+ if (IsDefinition) {
if (!DeclaratorInfo.isFunctionDeclarator()) {
Diag(Tok, diag::err_func_def_no_params);
ConsumeBrace();
@@ -1604,10 +1774,12 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS,
return;
}
- ParseCXXInlineMethodDef(AS, DeclaratorInfo, TemplateInfo, VS);
- // Consume the optional ';'
- if (Tok.is(tok::semi))
+ ParseCXXInlineMethodDef(AS, DeclaratorInfo, TemplateInfo, VS, Init);
+
+ // Consume the ';' - it's optional unless we have a delete or default
+ if (Tok.is(tok::semi)) {
ConsumeToken();
+ }
return;
}
@@ -1619,13 +1791,11 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS,
llvm::SmallVector<Decl *, 8> DeclsInGroup;
ExprResult BitfieldSize;
- ExprResult Init;
- bool Deleted = false;
while (1) {
// member-declarator:
// declarator pure-specifier[opt]
- // declarator constant-initializer[opt]
+ // declarator brace-or-equal-initializer[opt]
// identifier[opt] ':' constant-expression
if (Tok.is(tok::colon)) {
ConsumeToken();
@@ -1634,31 +1804,6 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS,
SkipUntil(tok::comma, true, true);
}
- ParseOptionalCXX0XVirtSpecifierSeq(VS);
-
- // pure-specifier:
- // '= 0'
- //
- // constant-initializer:
- // '=' constant-expression
- //
- // defaulted/deleted function-definition:
- // '=' 'default' [TODO]
- // '=' 'delete'
- if (Tok.is(tok::equal)) {
- ConsumeToken();
- if (Tok.is(tok::kw_delete)) {
- if (!getLang().CPlusPlus0x)
- Diag(Tok, diag::warn_deleted_function_accepted_as_extension);
- ConsumeToken();
- Deleted = true;
- } else {
- Init = ParseInitializer();
- if (Init.isInvalid())
- SkipUntil(tok::comma, true, true);
- }
- }
-
// If a simple-asm-expr is present, parse it.
if (Tok.is(tok::kw_asm)) {
SourceLocation Loc;
@@ -1673,6 +1818,30 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS,
// If attributes exist after the declarator, parse them.
MaybeParseGNUAttributes(DeclaratorInfo);
+ // FIXME: When g++ adds support for this, we'll need to check whether it
+ // goes before or after the GNU attributes and __asm__.
+ ParseOptionalCXX0XVirtSpecifierSeq(VS);
+
+ bool HasDeferredInitializer = false;
+ if (Tok.is(tok::equal) || Tok.is(tok::l_brace)) {
+ if (BitfieldSize.get()) {
+ Diag(Tok, diag::err_bitfield_member_init);
+ SkipUntil(tok::comma, true, true);
+ } else {
+ HasDeferredInitializer = !DeclaratorInfo.isFunctionDeclarator() &&
+ DeclaratorInfo.getDeclSpec().getStorageClassSpec()
+ != DeclSpec::SCS_static;
+
+ if (!HasDeferredInitializer) {
+ SourceLocation EqualLoc;
+ Init = ParseCXXMemberInitializer(
+ DeclaratorInfo.isFunctionDeclarator(), EqualLoc);
+ if (Init.isInvalid())
+ SkipUntil(tok::comma, true, true);
+ }
+ }
+ }
+
// NOTE: If Sema is the Action module and declarator is an instance field,
// this call will *not* return the created decl; It will return null.
// See Sema::ActOnCXXMemberDeclarator for details.
@@ -1689,8 +1858,8 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS,
move(TemplateParams),
BitfieldSize.release(),
VS, Init.release(),
- /*IsDefinition*/Deleted,
- Deleted);
+ HasDeferredInitializer,
+ /*IsDefinition*/ false);
}
if (ThisDecl)
DeclsInGroup.push_back(ThisDecl);
@@ -1703,6 +1872,24 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS,
DeclaratorInfo.complete(ThisDecl);
+ if (HasDeferredInitializer) {
+ if (!getLang().CPlusPlus0x)
+ Diag(Tok, diag::warn_nonstatic_member_init_accepted_as_extension);
+
+ if (DeclaratorInfo.isArrayOfUnknownBound()) {
+ // C++0x [dcl.array]p3: An array bound may also be omitted when the
+ // declarator is followed by an initializer.
+ //
+ // A brace-or-equal-initializer for a member-declarator is not an
+ // initializer in the gramamr, so this is ill-formed.
+ Diag(Tok, diag::err_incomplete_array_member_init);
+ SkipUntil(tok::comma, true, true);
+ // Avoid later warnings about a class member of incomplete type.
+ ThisDecl->setInvalidDecl();
+ } else
+ ParseCXXNonStaticMemberInitializer(ThisDecl);
+ }
+
// If we don't have a comma, it is either the end of the list (a ';')
// or an error, bail out.
if (Tok.isNot(tok::comma))
@@ -1716,7 +1903,6 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS,
VS.clear();
BitfieldSize = 0;
Init = 0;
- Deleted = false;
// Attributes are only allowed on the second declarator.
MaybeParseGNUAttributes(DeclaratorInfo);
@@ -1737,6 +1923,66 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS,
DeclsInGroup.size());
}
+/// ParseCXXMemberInitializer - Parse the brace-or-equal-initializer or
+/// pure-specifier. Also detect and reject any attempted defaulted/deleted
+/// function definition. The location of the '=', if any, will be placed in
+/// EqualLoc.
+///
+/// pure-specifier:
+/// '= 0'
+///
+/// brace-or-equal-initializer:
+/// '=' initializer-expression
+/// braced-init-list [TODO]
+///
+/// initializer-clause:
+/// assignment-expression
+/// braced-init-list [TODO]
+///
+/// defaulted/deleted function-definition:
+/// '=' 'default'
+/// '=' 'delete'
+///
+/// Prior to C++0x, the assignment-expression in an initializer-clause must
+/// be a constant-expression.
+ExprResult Parser::ParseCXXMemberInitializer(bool IsFunction,
+ SourceLocation &EqualLoc) {
+ assert((Tok.is(tok::equal) || Tok.is(tok::l_brace))
+ && "Data member initializer not starting with '=' or '{'");
+
+ if (Tok.is(tok::equal)) {
+ EqualLoc = ConsumeToken();
+ if (Tok.is(tok::kw_delete)) {
+ // In principle, an initializer of '= delete p;' is legal, but it will
+ // never type-check. It's better to diagnose it as an ill-formed expression
+ // than as an ill-formed deleted non-function member.
+ // An initializer of '= delete p, foo' will never be parsed, because
+ // a top-level comma always ends the initializer expression.
+ const Token &Next = NextToken();
+ if (IsFunction || Next.is(tok::semi) || Next.is(tok::comma) ||
+ Next.is(tok::eof)) {
+ if (IsFunction)
+ Diag(ConsumeToken(), diag::err_default_delete_in_multiple_declaration)
+ << 1 /* delete */;
+ else
+ Diag(ConsumeToken(), diag::err_deleted_non_function);
+ return ExprResult();
+ }
+ } else if (Tok.is(tok::kw_default)) {
+ Diag(ConsumeToken(), diag::err_default_special_members);
+ if (IsFunction)
+ Diag(Tok, diag::err_default_delete_in_multiple_declaration)
+ << 0 /* default */;
+ else
+ Diag(ConsumeToken(), diag::err_default_special_members);
+ return ExprResult();
+ }
+
+ return ParseInitializer();
+ } else
+ return ExprError(Diag(Tok, diag::err_generalized_initializer_lists));
+}
+
/// ParseCXXMemberSpecification - Parse the class definition.
///
/// member-specification:
@@ -1839,6 +2085,12 @@ void Parser::ParseCXXMemberSpecification(SourceLocation RecordLoc,
while (Tok.isNot(tok::r_brace) && Tok.isNot(tok::eof)) {
// Each iteration of this loop reads one member-declaration.
+ if (getLang().Microsoft && (Tok.is(tok::kw___if_exists) ||
+ Tok.is(tok::kw___if_not_exists))) {
+ ParseMicrosoftIfExistsClassDeclaration((DeclSpec::TST)TagType, CurAS);
+ continue;
+ }
+
// Check for extraneous top-level semicolon.
if (Tok.is(tok::semi)) {
Diag(Tok, diag::ext_extra_struct_semi)
@@ -1882,19 +2134,20 @@ void Parser::ParseCXXMemberSpecification(SourceLocation RecordLoc,
LBraceLoc, RBraceLoc,
attrs.getList());
- // C++ 9.2p2: Within the class member-specification, the class is regarded as
- // complete within function bodies, default arguments,
- // exception-specifications, and constructor ctor-initializers (including
- // such things in nested classes).
+ // C++0x [class.mem]p2: Within the class member-specification, the class is
+ // regarded as complete within function bodies, default arguments, exception-
+ // specifications, and brace-or-equal-initializers for non-static data
+ // members (including such things in nested classes).
//
- // FIXME: Only function bodies and constructor ctor-initializers are
- // parsed correctly, fix the rest.
+ // FIXME: Only function bodies and brace-or-equal-initializers are currently
+ // handled. Fix the others!
if (TagDecl && NonNestedClass) {
// We are not inside a nested class. This class and its nested classes
// are complete and we can parse the delayed portions of method
// declarations and the lexed inline method definitions.
SourceLocation SavedPrevTokLocation = PrevTokLocation;
ParseLexedMethodDeclarations(getCurrentClass());
+ ParseLexedMemberInitializers(getCurrentClass());
ParseLexedMethodDefs(getCurrentClass());
PrevTokLocation = SavedPrevTokLocation;
}
@@ -1982,6 +2235,7 @@ void Parser::ParseConstructorInitializer(Decl *ConstructorDecl) {
///
/// [C++] mem-initializer:
/// mem-initializer-id '(' expression-list[opt] ')'
+/// [C++0x] mem-initializer-id braced-init-list
///
/// [C++] mem-initializer-id:
/// '::'[opt] nested-name-specifier[opt] class-name
@@ -2012,31 +2266,37 @@ Parser::MemInitResult Parser::ParseMemInitializer(Decl *ConstructorDecl) {
SourceLocation IdLoc = ConsumeToken();
// Parse the '('.
- if (Tok.isNot(tok::l_paren)) {
- Diag(Tok, diag::err_expected_lparen);
+ if (getLang().CPlusPlus0x && Tok.is(tok::l_brace)) {
+ // FIXME: Do something with the braced-init-list.
+ ParseBraceInitializer();
return true;
- }
- SourceLocation LParenLoc = ConsumeParen();
+ } else if(Tok.is(tok::l_paren)) {
+ SourceLocation LParenLoc = ConsumeParen();
- // Parse the optional expression-list.
- ExprVector ArgExprs(Actions);
- CommaLocsTy CommaLocs;
- if (Tok.isNot(tok::r_paren) && ParseExpressionList(ArgExprs, CommaLocs)) {
- SkipUntil(tok::r_paren);
- return true;
- }
+ // Parse the optional expression-list.
+ ExprVector ArgExprs(Actions);
+ CommaLocsTy CommaLocs;
+ if (Tok.isNot(tok::r_paren) && ParseExpressionList(ArgExprs, CommaLocs)) {
+ SkipUntil(tok::r_paren);
+ return true;
+ }
- SourceLocation RParenLoc = MatchRHSPunctuation(tok::r_paren, LParenLoc);
+ SourceLocation RParenLoc = MatchRHSPunctuation(tok::r_paren, LParenLoc);
- SourceLocation EllipsisLoc;
- if (Tok.is(tok::ellipsis))
- EllipsisLoc = ConsumeToken();
-
- return Actions.ActOnMemInitializer(ConstructorDecl, getCurScope(), SS, II,
- TemplateTypeTy, IdLoc,
- LParenLoc, ArgExprs.take(),
- ArgExprs.size(), RParenLoc,
- EllipsisLoc);
+ SourceLocation EllipsisLoc;
+ if (Tok.is(tok::ellipsis))
+ EllipsisLoc = ConsumeToken();
+
+ return Actions.ActOnMemInitializer(ConstructorDecl, getCurScope(), SS, II,
+ TemplateTypeTy, IdLoc,
+ LParenLoc, ArgExprs.take(),
+ ArgExprs.size(), RParenLoc,
+ EllipsisLoc);
+ }
+
+ Diag(Tok, getLang().CPlusPlus0x ? diag::err_expected_lparen_or_lbrace
+ : diag::err_expected_lparen);
+ return true;
}
/// \brief Parse a C++ exception-specification if present (C++0x [except.spec]).
@@ -2438,3 +2698,64 @@ void Parser::ParseMicrosoftAttributes(ParsedAttributes &attrs,
ExpectAndConsume(tok::r_square, diag::err_expected_rsquare);
}
}
+
+void Parser::ParseMicrosoftIfExistsClassDeclaration(DeclSpec::TST TagType,
+ AccessSpecifier& CurAS) {
+ bool Result;
+ if (ParseMicrosoftIfExistsCondition(Result))
+ return;
+
+ if (Tok.isNot(tok::l_brace)) {
+ Diag(Tok, diag::err_expected_lbrace);
+ return;
+ }
+ ConsumeBrace();
+
+ // Condition is false skip all inside the {}.
+ if (!Result) {
+ SkipUntil(tok::r_brace, false);
+ return;
+ }
+
+ // Condition is true, parse the declaration.
+ while (Tok.isNot(tok::r_brace)) {
+
+ // __if_exists, __if_not_exists can nest.
+ if ((Tok.is(tok::kw___if_exists) || Tok.is(tok::kw___if_not_exists))) {
+ ParseMicrosoftIfExistsClassDeclaration((DeclSpec::TST)TagType, CurAS);
+ continue;
+ }
+
+ // Check for extraneous top-level semicolon.
+ if (Tok.is(tok::semi)) {
+ Diag(Tok, diag::ext_extra_struct_semi)
+ << DeclSpec::getSpecifierName((DeclSpec::TST)TagType)
+ << FixItHint::CreateRemoval(Tok.getLocation());
+ ConsumeToken();
+ continue;
+ }
+
+ AccessSpecifier AS = getAccessSpecifierIfPresent();
+ if (AS != AS_none) {
+ // Current token is a C++ access specifier.
+ CurAS = AS;
+ SourceLocation ASLoc = Tok.getLocation();
+ ConsumeToken();
+ if (Tok.is(tok::colon))
+ Actions.ActOnAccessSpecifier(AS, ASLoc, Tok.getLocation());
+ else
+ Diag(Tok, diag::err_expected_colon);
+ ConsumeToken();
+ continue;
+ }
+
+ // Parse all the comma separated declarators.
+ ParseCXXClassMemberDeclaration(CurAS);
+ }
+
+ if (Tok.isNot(tok::r_brace)) {
+ Diag(Tok, diag::err_expected_rbrace);
+ return;
+ }
+ ConsumeBrace();
+}
diff --git a/lib/Parse/ParseExpr.cpp b/lib/Parse/ParseExpr.cpp
index 91fe1e1..4e94ed9 100644
--- a/lib/Parse/ParseExpr.cpp
+++ b/lib/Parse/ParseExpr.cpp
@@ -480,7 +480,9 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression,
/// [OBJC] '@encode' '(' type-name ')'
/// [OBJC] objc-string-literal
/// [C++] simple-type-specifier '(' expression-list[opt] ')' [C++ 5.2.3]
+/// [C++0x] simple-type-specifier braced-init-list [C++ 5.2.3]
/// [C++] typename-specifier '(' expression-list[opt] ')' [C++ 5.2.3]
+/// [C++0x] typename-specifier braced-init-list [C++ 5.2.3]
/// [C++] 'const_cast' '<' type-name '>' '(' expression ')' [C++ 5.2p1]
/// [C++] 'dynamic_cast' '<' type-name '>' '(' expression ')' [C++ 5.2p1]
/// [C++] 'reinterpret_cast' '<' type-name '>' '(' expression ')' [C++ 5.2p1]
@@ -566,6 +568,9 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression,
/// '__is_trivial'
/// '__is_union'
///
+/// [Clang] unary-type-trait:
+/// '__trivially_copyable'
+///
/// binary-type-trait:
/// [GNU] '__is_base_of'
/// [MS] '__is_convertible_to'
@@ -782,6 +787,7 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression,
case tok::kw___builtin_va_arg:
case tok::kw___builtin_offsetof:
case tok::kw___builtin_choose_expr:
+ case tok::kw___builtin_astype: // primary-expression: [OCL] as_type()
return ParseBuiltinPrimaryExpression();
case tok::kw___null:
return Actions.ActOnGNUNullExpr(ConsumeToken());
@@ -919,15 +925,18 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression,
if (SavedKind == tok::kw_typename) {
// postfix-expression: typename-specifier '(' expression-list[opt] ')'
+ // typename-specifier braced-init-list
if (TryAnnotateTypeOrScopeToken())
return ExprError();
}
// postfix-expression: simple-type-specifier '(' expression-list[opt] ')'
+ // simple-type-specifier braced-init-list
//
DeclSpec DS(AttrFactory);
ParseCXXSimpleTypeSpecifier(DS);
- if (Tok.isNot(tok::l_paren))
+ if (Tok.isNot(tok::l_paren) &&
+ (!getLang().CPlusPlus0x || Tok.isNot(tok::l_brace)))
return ExprError(Diag(Tok, diag::err_expected_lparen_after_type)
<< DS.getSourceRange());
@@ -1060,6 +1069,7 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression,
case tok::kw___is_pod:
case tok::kw___is_polymorphic:
case tok::kw___is_trivial:
+ case tok::kw___is_trivially_copyable:
case tok::kw___is_union:
case tok::kw___has_trivial_constructor:
case tok::kw___has_trivial_copy:
@@ -1117,6 +1127,7 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression,
/// postfix-expression: [C99 6.5.2]
/// primary-expression
/// postfix-expression '[' expression ']'
+/// postfix-expression '[' braced-init-list ']'
/// postfix-expression '(' argument-expression-list[opt] ')'
/// postfix-expression '.' identifier
/// postfix-expression '->' identifier
@@ -1172,7 +1183,11 @@ Parser::ParsePostfixExpressionSuffix(ExprResult LHS) {
return move(LHS);
Loc = ConsumeBracket();
- ExprResult Idx(ParseExpression());
+ ExprResult Idx;
+ if (getLang().CPlusPlus0x && Tok.is(tok::l_brace))
+ Idx = ParseBraceInitializer();
+ else
+ Idx = ParseExpression();
SourceLocation RLoc = Tok.getLocation();
@@ -1529,6 +1544,7 @@ ExprResult Parser::ParseUnaryExprOrTypeTraitExpression() {
/// [GNU] '__builtin_choose_expr' '(' assign-expr ',' assign-expr ','
/// assign-expr ')'
/// [GNU] '__builtin_types_compatible_p' '(' type-name ',' type-name ')'
+/// [OCL] '__builtin_astype' '(' type-name expr ')'
///
/// [GNU] offsetof-member-designator:
/// [GNU] identifier
@@ -1673,7 +1689,35 @@ ExprResult Parser::ParseBuiltinPrimaryExpression() {
Expr2.take(), ConsumeParen());
break;
}
+ case tok::kw___builtin_astype: {
+ // The first argument is an expression to be converted, followed by a comma.
+ ExprResult Expr(ParseAssignmentExpression());
+ if (Expr.isInvalid()) {
+ SkipUntil(tok::r_paren);
+ return ExprError();
+ }
+
+ if (ExpectAndConsume(tok::comma, diag::err_expected_comma, "",
+ tok::r_paren))
+ return ExprError();
+
+ // Second argument is the type to bitcast to.
+ TypeResult DestTy = ParseTypeName();
+ if (DestTy.isInvalid())
+ return ExprError();
+
+ // Attempt to consume the r-paren.
+ if (Tok.isNot(tok::r_paren)) {
+ Diag(Tok, diag::err_expected_rparen);
+ SkipUntil(tok::r_paren);
+ return ExprError();
+ }
+
+ Res = Actions.ActOnAsTypeExpr(Expr.take(), DestTy.get(), StartLoc,
+ ConsumeParen());
+ break;
}
+}
if (Res.isInvalid())
return ExprError();
@@ -1987,8 +2031,19 @@ ExprResult Parser::ParseGenericSelectionExpression() {
/// argument-expression-list , assignment-expression
///
/// [C++] expression-list:
-/// [C++] assignment-expression ...[opt]
-/// [C++] expression-list , assignment-expression ...[opt]
+/// [C++] assignment-expression
+/// [C++] expression-list , assignment-expression
+///
+/// [C++0x] expression-list:
+/// [C++0x] initializer-list
+///
+/// [C++0x] initializer-list
+/// [C++0x] initializer-clause ...[opt]
+/// [C++0x] initializer-list , initializer-clause ...[opt]
+///
+/// [C++0x] initializer-clause:
+/// [C++0x] assignment-expression
+/// [C++0x] braced-init-list
///
bool Parser::ParseExpressionList(llvm::SmallVectorImpl<Expr*> &Exprs,
llvm::SmallVectorImpl<SourceLocation> &CommaLocs,
@@ -2005,8 +2060,13 @@ bool Parser::ParseExpressionList(llvm::SmallVectorImpl<Expr*> &Exprs,
Actions.CodeCompleteOrdinaryName(getCurScope(), Sema::PCC_Expression);
ConsumeCodeCompletionToken();
}
-
- ExprResult Expr(ParseAssignmentExpression());
+
+ ExprResult Expr;
+ if (getLang().CPlusPlus0x && Tok.is(tok::l_brace))
+ Expr = ParseBraceInitializer();
+ else
+ Expr = ParseAssignmentExpression();
+
if (Tok.is(tok::ellipsis))
Expr = Actions.ActOnPackExpansion(Expr.get(), ConsumeToken());
if (Expr.isInvalid())
diff --git a/lib/Parse/ParseExprCXX.cpp b/lib/Parse/ParseExprCXX.cpp
index 8bf6f63..eab7114 100644
--- a/lib/Parse/ParseExprCXX.cpp
+++ b/lib/Parse/ParseExprCXX.cpp
@@ -280,8 +280,11 @@ bool Parser::ParseOptionalCXXScopeSpecifier(CXXScopeSpec &SS,
: TemplateId->TemplateNameLoc;
SS.SetInvalid(SourceRange(StartLoc, CCLoc));
}
-
- TemplateId->Destroy();
+
+ // If we are caching tokens we will process the TemplateId again,
+ // otherwise destroy it.
+ if (!PP.isBacktrackEnabled())
+ TemplateId->Destroy();
continue;
}
@@ -806,42 +809,55 @@ ExprResult Parser::ParseCXXThis() {
/// Can be interpreted either as function-style casting ("int(x)")
/// or class type construction ("ClassType(x,y,z)")
/// or creation of a value-initialized type ("int()").
+/// See [C++ 5.2.3].
///
/// postfix-expression: [C++ 5.2p1]
-/// simple-type-specifier '(' expression-list[opt] ')' [C++ 5.2.3]
-/// typename-specifier '(' expression-list[opt] ')' [TODO]
+/// simple-type-specifier '(' expression-list[opt] ')'
+/// [C++0x] simple-type-specifier braced-init-list
+/// typename-specifier '(' expression-list[opt] ')'
+/// [C++0x] typename-specifier braced-init-list
///
ExprResult
Parser::ParseCXXTypeConstructExpression(const DeclSpec &DS) {
Declarator DeclaratorInfo(DS, Declarator::TypeNameContext);
ParsedType TypeRep = Actions.ActOnTypeName(getCurScope(), DeclaratorInfo).get();
- assert(Tok.is(tok::l_paren) && "Expected '('!");
- GreaterThanIsOperatorScope G(GreaterThanIsOperator, true);
+ assert((Tok.is(tok::l_paren) ||
+ (getLang().CPlusPlus0x && Tok.is(tok::l_brace)))
+ && "Expected '(' or '{'!");
- SourceLocation LParenLoc = ConsumeParen();
+ if (Tok.is(tok::l_brace)) {
- ExprVector Exprs(Actions);
- CommaLocsTy CommaLocs;
+ // FIXME: Convert to a proper type construct expression.
+ return ParseBraceInitializer();
- if (Tok.isNot(tok::r_paren)) {
- if (ParseExpressionList(Exprs, CommaLocs)) {
- SkipUntil(tok::r_paren);
- return ExprError();
+ } else {
+ GreaterThanIsOperatorScope G(GreaterThanIsOperator, true);
+
+ SourceLocation LParenLoc = ConsumeParen();
+
+ ExprVector Exprs(Actions);
+ CommaLocsTy CommaLocs;
+
+ if (Tok.isNot(tok::r_paren)) {
+ if (ParseExpressionList(Exprs, CommaLocs)) {
+ SkipUntil(tok::r_paren);
+ return ExprError();
+ }
}
- }
- // Match the ')'.
- SourceLocation RParenLoc = MatchRHSPunctuation(tok::r_paren, LParenLoc);
+ // Match the ')'.
+ SourceLocation RParenLoc = MatchRHSPunctuation(tok::r_paren, LParenLoc);
- // TypeRep could be null, if it references an invalid typedef.
- if (!TypeRep)
- return ExprError();
+ // TypeRep could be null, if it references an invalid typedef.
+ if (!TypeRep)
+ return ExprError();
- assert((Exprs.size() == 0 || Exprs.size()-1 == CommaLocs.size())&&
- "Unexpected number of commas!");
- return Actions.ActOnCXXTypeConstructExpr(TypeRep, LParenLoc, move_arg(Exprs),
- RParenLoc);
+ assert((Exprs.size() == 0 || Exprs.size()-1 == CommaLocs.size())&&
+ "Unexpected number of commas!");
+ return Actions.ActOnCXXTypeConstructExpr(TypeRep, LParenLoc, move_arg(Exprs),
+ RParenLoc);
+ }
}
/// ParseCXXCondition - if/switch/while condition expression.
@@ -959,6 +975,7 @@ bool Parser::isCXXSimpleTypeSpecifier() const {
case tok::kw_bool:
case tok::kw_decltype:
case tok::kw_typeof:
+ case tok::kw___underlying_type:
return true;
default:
@@ -1723,7 +1740,7 @@ bool Parser::ParseUnqualifiedId(CXXScopeSpec &SS, bool EnteringContext,
///
/// new-initializer:
/// '(' expression-list[opt] ')'
-/// [C++0x] braced-init-list [TODO]
+/// [C++0x] braced-init-list
///
ExprResult
Parser::ParseCXXNewExpression(bool UseGlobal, SourceLocation Start) {
@@ -1812,6 +1829,9 @@ Parser::ParseCXXNewExpression(bool UseGlobal, SourceLocation Start) {
SkipUntil(tok::semi, /*StopAtSemi=*/true, /*DontConsume=*/true);
return ExprError();
}
+ } else if (Tok.is(tok::l_brace)) {
+ // FIXME: Have to communicate the init-list to ActOnCXXNew.
+ ParseBraceInitializer();
}
return Actions.ActOnCXXNew(Start, UseGlobal, PlacementLParen,
@@ -1921,7 +1941,8 @@ static UnaryTypeTrait UnaryTypeTraitFromTokKind(tok::TokenKind kind) {
case tok::kw___has_nothrow_constructor: return UTT_HasNothrowConstructor;
case tok::kw___has_nothrow_copy: return UTT_HasNothrowCopy;
case tok::kw___has_trivial_assign: return UTT_HasTrivialAssign;
- case tok::kw___has_trivial_constructor: return UTT_HasTrivialConstructor;
+ case tok::kw___has_trivial_constructor:
+ return UTT_HasTrivialDefaultConstructor;
case tok::kw___has_trivial_copy: return UTT_HasTrivialCopy;
case tok::kw___has_trivial_destructor: return UTT_HasTrivialDestructor;
case tok::kw___has_virtual_destructor: return UTT_HasVirtualDestructor;
@@ -1954,6 +1975,7 @@ static UnaryTypeTrait UnaryTypeTraitFromTokKind(tok::TokenKind kind) {
case tok::kw___is_signed: return UTT_IsSigned;
case tok::kw___is_standard_layout: return UTT_IsStandardLayout;
case tok::kw___is_trivial: return UTT_IsTrivial;
+ case tok::kw___is_trivially_copyable: return UTT_IsTriviallyCopyable;
case tok::kw___is_union: return UTT_IsUnion;
case tok::kw___is_unsigned: return UTT_IsUnsigned;
case tok::kw___is_void: return UTT_IsVoid;
diff --git a/lib/Parse/ParseObjc.cpp b/lib/Parse/ParseObjc.cpp
index fdbedc5..a8c18c0 100644
--- a/lib/Parse/ParseObjc.cpp
+++ b/lib/Parse/ParseObjc.cpp
@@ -874,8 +874,8 @@ Decl *Parser::ParseObjCMethodDecl(SourceLocation mLoc,
Selector Sel = PP.getSelectorTable().getNullarySelector(SelIdent);
Decl *Result
= Actions.ActOnMethodDeclaration(getCurScope(), mLoc, Tok.getLocation(),
- mType, IDecl, DSRet, ReturnType, Sel,
- 0,
+ mType, IDecl, DSRet, ReturnType,
+ selLoc, Sel, 0,
CParamInfo.data(), CParamInfo.size(),
methodAttrs.getList(), MethodImplKind,
false, MethodDefinition);
@@ -1000,8 +1000,8 @@ Decl *Parser::ParseObjCMethodDecl(SourceLocation mLoc,
&KeyIdents[0]);
Decl *Result
= Actions.ActOnMethodDeclaration(getCurScope(), mLoc, Tok.getLocation(),
- mType, IDecl, DSRet, ReturnType, Sel,
- &ArgInfos[0],
+ mType, IDecl, DSRet, ReturnType,
+ selLoc, Sel, &ArgInfos[0],
CParamInfo.data(), CParamInfo.size(),
methodAttrs.getList(),
MethodImplKind, isVariadic, MethodDefinition);
diff --git a/lib/Parse/ParsePragma.cpp b/lib/Parse/ParsePragma.cpp
index 46225c8..c30ab75 100644
--- a/lib/Parse/ParsePragma.cpp
+++ b/lib/Parse/ParsePragma.cpp
@@ -295,7 +295,6 @@ void PragmaUnusedHandler::HandlePragma(Preprocessor &PP,
PP.Diag(Tok.getLocation(), diag::warn_pragma_expected_lparen) << "unused";
return;
}
- SourceLocation LParenLoc = Tok.getLocation();
// Lex the declaration reference(s).
llvm::SmallVector<Token, 5> Identifiers;
diff --git a/lib/Parse/ParseStmt.cpp b/lib/Parse/ParseStmt.cpp
index f0ab531..6cc8b57 100644
--- a/lib/Parse/ParseStmt.cpp
+++ b/lib/Parse/ParseStmt.cpp
@@ -741,6 +741,12 @@ StmtResult Parser::ParseCompoundStatementBody(bool isStmtExpr) {
continue;
}
+ if (getLang().Microsoft && (Tok.is(tok::kw___if_exists) ||
+ Tok.is(tok::kw___if_not_exists))) {
+ ParseMicrosoftIfExistsStatement(Stmts);
+ continue;
+ }
+
StmtResult R;
if (Tok.isNot(tok::kw___extension__)) {
R = ParseStatementOrDeclaration(Stmts, false);
@@ -2000,3 +2006,34 @@ StmtResult Parser::ParseCXXCatchBlock() {
return Actions.ActOnCXXCatchBlock(CatchLoc, ExceptionDecl, Block.take());
}
+
+void Parser::ParseMicrosoftIfExistsStatement(StmtVector &Stmts) {
+ bool Result;
+ if (ParseMicrosoftIfExistsCondition(Result))
+ return;
+
+ if (Tok.isNot(tok::l_brace)) {
+ Diag(Tok, diag::err_expected_lbrace);
+ return;
+ }
+ ConsumeBrace();
+
+ // Condition is false skip all inside the {}.
+ if (!Result) {
+ SkipUntil(tok::r_brace, false);
+ return;
+ }
+
+ // Condition is true, parse the statements.
+ while (Tok.isNot(tok::r_brace)) {
+ StmtResult R = ParseStatementOrDeclaration(Stmts, false);
+ if (R.isUsable())
+ Stmts.push_back(R.release());
+ }
+
+ if (Tok.isNot(tok::r_brace)) {
+ Diag(Tok, diag::err_expected_rbrace);
+ return;
+ }
+ ConsumeBrace();
+}
diff --git a/lib/Parse/ParseTemplate.cpp b/lib/Parse/ParseTemplate.cpp
index 12e38da..aa89d75 100644
--- a/lib/Parse/ParseTemplate.cpp
+++ b/lib/Parse/ParseTemplate.cpp
@@ -905,10 +905,10 @@ ParsedTemplateArgument Parser::ParseTemplateTemplateArgument() {
// C++0x [temp.arg.template]p1:
// A template-argument for a template template-parameter shall be the name
- // of a class template or a template alias, expressed as id-expression.
+ // of a class template or an alias template, expressed as id-expression.
//
- // We parse an id-expression that refers to a class template or template
- // alias. The grammar we parse is:
+ // We parse an id-expression that refers to a class template or alias
+ // template. The grammar we parse is:
//
// nested-name-specifier[opt] template[opt] identifier ...[opt]
//
@@ -969,7 +969,7 @@ ParsedTemplateArgument Parser::ParseTemplateTemplateArgument() {
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.
+ // (C++0x) alias template.
Result = ParsedTemplateArgument(SS, Template, Name.StartLocation);
}
}
diff --git a/lib/Parse/ParseTentative.cpp b/lib/Parse/ParseTentative.cpp
index 1c4e2b3..78d2c90 100644
--- a/lib/Parse/ParseTentative.cpp
+++ b/lib/Parse/ParseTentative.cpp
@@ -664,6 +664,7 @@ Parser::isExpressionOrTypeSpecifierSimple(tok::TokenKind Kind) {
case tok::kw___is_pod:
case tok::kw___is_polymorphic:
case tok::kw___is_trivial:
+ case tok::kw___is_trivially_copyable:
case tok::kw___is_union:
case tok::kw___uuidof:
return TPResult::True();
@@ -693,6 +694,7 @@ Parser::isExpressionOrTypeSpecifierSimple(tok::TokenKind Kind) {
case tok::kw_char16_t:
case tok::kw_char32_t:
case tok::kw_decltype:
+ case tok::kw___underlying_type:
case tok::kw_thread_local:
case tok::kw__Decimal32:
case tok::kw__Decimal64:
@@ -1011,6 +1013,10 @@ Parser::TPResult Parser::isCXXDeclarationSpecifier() {
case tok::kw_decltype:
return TPResult::True();
+ // C++0x type traits support
+ case tok::kw___underlying_type:
+ return TPResult::True();
+
default:
return TPResult::False();
}
diff --git a/lib/Parse/Parser.cpp b/lib/Parse/Parser.cpp
index 4d08699..f19472c 100644
--- a/lib/Parse/Parser.cpp
+++ b/lib/Parse/Parser.cpp
@@ -20,6 +20,7 @@
#include "RAIIObjectsForParser.h"
#include "ParsePragma.h"
#include "clang/AST/DeclTemplate.h"
+#include "clang/AST/ASTConsumer.h"
using namespace clang;
Parser::Parser(Preprocessor &pp, Sema &actions)
@@ -350,7 +351,23 @@ void Parser::ExitScope() {
ScopeCache[NumCachedScopes++] = OldScope;
}
+/// Set the flags for the current scope to ScopeFlags. If ManageFlags is false,
+/// this object does nothing.
+Parser::ParseScopeFlags::ParseScopeFlags(Parser *Self, unsigned ScopeFlags,
+ bool ManageFlags)
+ : CurScope(ManageFlags ? Self->getCurScope() : 0) {
+ if (CurScope) {
+ OldFlags = CurScope->getFlags();
+ CurScope->setFlags(ScopeFlags);
+ }
+}
+/// Restore the flags for the current scope to what they were before this
+/// object overrode them.
+Parser::ParseScopeFlags::~ParseScopeFlags() {
+ if (CurScope)
+ CurScope->setFlags(OldFlags);
+}
//===----------------------------------------------------------------------===//
@@ -653,6 +670,11 @@ Parser::ParseExternalDeclaration(ParsedAttributesWithRange &attrs,
// FIXME: Detect C++ linkage specifications here?
goto dont_know;
+ case tok::kw___if_exists:
+ case tok::kw___if_not_exists:
+ ParseMicrosoftIfExistsExternalDeclaration();
+ return DeclGroupPtrTy();
+
default:
dont_know:
// We can't tell whether this is a function-definition or declaration yet.
@@ -671,7 +693,14 @@ Parser::ParseExternalDeclaration(ParsedAttributesWithRange &attrs,
/// \brief Determine whether the current token, if it occurs after a
/// declarator, continues a declaration or declaration list.
-bool Parser::isDeclarationAfterDeclarator() const {
+bool Parser::isDeclarationAfterDeclarator() {
+ // Check for '= delete' or '= default'
+ if (getLang().CPlusPlus && Tok.is(tok::equal)) {
+ const Token &KW = NextToken();
+ if (KW.is(tok::kw_default) || KW.is(tok::kw_delete))
+ return false;
+ }
+
return Tok.is(tok::equal) || // int X()= -> not a function def
Tok.is(tok::comma) || // int X(), -> not a function def
Tok.is(tok::semi) || // int X(); -> not a function def
@@ -692,6 +721,11 @@ bool Parser::isStartOfFunctionDefinition(const ParsingDeclarator &Declarator) {
if (!getLang().CPlusPlus &&
Declarator.getFunctionTypeInfo().isKNRPrototype())
return isDeclarationSpecifier();
+
+ if (getLang().CPlusPlus && Tok.is(tok::equal)) {
+ const Token &KW = NextToken();
+ return KW.is(tok::kw_default) || KW.is(tok::kw_delete);
+ }
return Tok.is(tok::colon) || // X() : Base() {} (used for ctors)
Tok.is(tok::kw_try); // X() try { ... }
@@ -814,11 +848,13 @@ Decl *Parser::ParseFunctionDefinition(ParsingDeclarator &D,
if (FTI.isKNRPrototype())
ParseKNRParamDeclarations(D);
+
// We should have either an opening brace or, in a C++ constructor,
// we may have a colon.
if (Tok.isNot(tok::l_brace) &&
(!getLang().CPlusPlus ||
- (Tok.isNot(tok::colon) && Tok.isNot(tok::kw_try)))) {
+ (Tok.isNot(tok::colon) && Tok.isNot(tok::kw_try) &&
+ Tok.isNot(tok::equal)))) {
Diag(Tok, diag::err_expected_fn_body);
// Skip over garbage, until we get to '{'. Don't eat the '{'.
@@ -866,7 +902,6 @@ Decl *Parser::ParseFunctionDefinition(ParsingDeclarator &D,
return DP;
}
-
// Enter a scope for the function body.
ParseScope BodyScope(this, Scope::FnScope|Scope::DeclScope);
@@ -887,6 +922,43 @@ Decl *Parser::ParseFunctionDefinition(ParsingDeclarator &D,
// safe because we're always the sole owner.
D.getMutableDeclSpec().abort();
+ if (Tok.is(tok::equal)) {
+ assert(getLang().CPlusPlus && "Only C++ function definitions have '='");
+ ConsumeToken();
+
+ Actions.ActOnFinishFunctionBody(Res, 0, false);
+
+ bool Delete = false;
+ SourceLocation KWLoc;
+ if (Tok.is(tok::kw_delete)) {
+ if (!getLang().CPlusPlus0x)
+ Diag(Tok, diag::warn_deleted_function_accepted_as_extension);
+
+ KWLoc = ConsumeToken();
+ Actions.SetDeclDeleted(Res, KWLoc);
+ Delete = true;
+ } else if (Tok.is(tok::kw_default)) {
+ if (!getLang().CPlusPlus0x)
+ Diag(Tok, diag::warn_defaulted_function_accepted_as_extension);
+
+ KWLoc = ConsumeToken();
+ Actions.SetDeclDefaulted(Res, KWLoc);
+ } else {
+ llvm_unreachable("function definition after = not 'delete' or 'default'");
+ }
+
+ if (Tok.is(tok::comma)) {
+ Diag(KWLoc, diag::err_default_delete_in_multiple_declaration)
+ << Delete;
+ SkipUntil(tok::semi);
+ } else {
+ ExpectAndConsume(tok::semi, diag::err_expected_semi_after,
+ Delete ? "delete" : "default", tok::semi);
+ }
+
+ return Res;
+ }
+
if (Tok.is(tok::kw_try))
return ParseFunctionTryBlock(Res, BodyScope);
@@ -1374,3 +1446,80 @@ void Parser::CodeCompleteMacroArgument(IdentifierInfo *Macro,
void Parser::CodeCompleteNaturalLanguage() {
Actions.CodeCompleteNaturalLanguage();
}
+
+bool Parser::ParseMicrosoftIfExistsCondition(bool& Result) {
+ assert((Tok.is(tok::kw___if_exists) || Tok.is(tok::kw___if_not_exists)) &&
+ "Expected '__if_exists' or '__if_not_exists'");
+ Token Condition = Tok;
+ SourceLocation IfExistsLoc = ConsumeToken();
+
+ SourceLocation LParenLoc = Tok.getLocation();
+ if (Tok.isNot(tok::l_paren)) {
+ Diag(Tok, diag::err_expected_lparen_after) << IfExistsLoc;
+ SkipUntil(tok::semi);
+ return true;
+ }
+ ConsumeParen(); // eat the '('.
+
+ // Parse nested-name-specifier.
+ CXXScopeSpec SS;
+ ParseOptionalCXXScopeSpecifier(SS, ParsedType(), false);
+
+ // Check nested-name specifier.
+ if (SS.isInvalid()) {
+ SkipUntil(tok::semi);
+ return true;
+ }
+
+ // Parse the unqualified-id.
+ UnqualifiedId Name;
+ if (ParseUnqualifiedId(SS, false, true, true, ParsedType(), Name)) {
+ SkipUntil(tok::semi);
+ return true;
+ }
+
+ if (MatchRHSPunctuation(tok::r_paren, LParenLoc).isInvalid())
+ return true;
+
+ // Check if the symbol exists.
+ bool Exist = Actions.CheckMicrosoftIfExistsSymbol(SS, Name);
+
+ Result = ((Condition.is(tok::kw___if_exists) && Exist) ||
+ (Condition.is(tok::kw___if_not_exists) && !Exist));
+
+ return false;
+}
+
+void Parser::ParseMicrosoftIfExistsExternalDeclaration() {
+ bool Result;
+ if (ParseMicrosoftIfExistsCondition(Result))
+ return;
+
+ if (Tok.isNot(tok::l_brace)) {
+ Diag(Tok, diag::err_expected_lbrace);
+ return;
+ }
+ ConsumeBrace();
+
+ // Condition is false skip all inside the {}.
+ if (!Result) {
+ SkipUntil(tok::r_brace, false);
+ return;
+ }
+
+ // Condition is true, parse the declaration.
+ while (Tok.isNot(tok::r_brace)) {
+ ParsedAttributesWithRange attrs(AttrFactory);
+ MaybeParseCXX0XAttributes(attrs);
+ MaybeParseMicrosoftAttributes(attrs);
+ DeclGroupPtrTy Result = ParseExternalDeclaration(attrs);
+ if (Result && !getCurScope()->getParent())
+ Actions.getASTConsumer().HandleTopLevelDecl(Result.get());
+ }
+
+ if (Tok.isNot(tok::r_brace)) {
+ Diag(Tok, diag::err_expected_rbrace);
+ return;
+ }
+ ConsumeBrace();
+}
diff --git a/lib/Rewrite/RewriteObjC.cpp b/lib/Rewrite/RewriteObjC.cpp
index d6e34ef..8cdb55a 100644
--- a/lib/Rewrite/RewriteObjC.cpp
+++ b/lib/Rewrite/RewriteObjC.cpp
@@ -2695,7 +2695,8 @@ QualType RewriteObjC::getSuperStructType() {
SourceLocation(), 0,
FieldTypes[i], 0,
/*BitWidth=*/0,
- /*Mutable=*/false));
+ /*Mutable=*/false,
+ /*HasInit=*/false));
}
SuperStructDecl->completeDefinition();
@@ -2727,7 +2728,8 @@ QualType RewriteObjC::getConstantStringStructType() {
SourceLocation(), 0,
FieldTypes[i], 0,
/*BitWidth=*/0,
- /*Mutable=*/true));
+ /*Mutable=*/true,
+ /*HasInit=*/false));
}
ConstantStringDecl->completeDefinition();
@@ -4709,7 +4711,8 @@ Stmt *RewriteObjC::SynthesizeBlockCall(CallExpr *Exp, const Expr *BlockExp) {
SourceLocation(),
&Context->Idents.get("FuncPtr"),
Context->VoidPtrTy, 0,
- /*BitWidth=*/0, /*Mutable=*/true);
+ /*BitWidth=*/0, /*Mutable=*/true,
+ /*HasInit=*/false);
MemberExpr *ME = new (Context) MemberExpr(PE, true, FD, SourceLocation(),
FD->getType(), VK_LValue,
OK_Ordinary);
@@ -4763,7 +4766,8 @@ Stmt *RewriteObjC::RewriteBlockDeclRefExpr(Expr *DeclRefExp) {
SourceLocation(),
&Context->Idents.get("__forwarding"),
Context->VoidPtrTy, 0,
- /*BitWidth=*/0, /*Mutable=*/true);
+ /*BitWidth=*/0, /*Mutable=*/true,
+ /*HasInit=*/false);
MemberExpr *ME = new (Context) MemberExpr(DeclRefExp, isArrow,
FD, SourceLocation(),
FD->getType(), VK_LValue,
@@ -4773,7 +4777,8 @@ Stmt *RewriteObjC::RewriteBlockDeclRefExpr(Expr *DeclRefExp) {
FD = FieldDecl::Create(*Context, 0, SourceLocation(), SourceLocation(),
&Context->Idents.get(Name),
Context->VoidPtrTy, 0,
- /*BitWidth=*/0, /*Mutable=*/true);
+ /*BitWidth=*/0, /*Mutable=*/true,
+ /*HasInit=*/false);
ME = new (Context) MemberExpr(ME, true, FD, SourceLocation(),
DeclRefExp->getType(), VK_LValue, OK_Ordinary);
diff --git a/lib/Sema/AnalysisBasedWarnings.cpp b/lib/Sema/AnalysisBasedWarnings.cpp
index e482172..9efae61 100644
--- a/lib/Sema/AnalysisBasedWarnings.cpp
+++ b/lib/Sema/AnalysisBasedWarnings.cpp
@@ -196,7 +196,12 @@ static ControlFlowKind CheckFallThrough(AnalysisContext &AC) {
continue;
}
Expr *CEE = C->getCallee()->IgnoreParenCasts();
- if (getFunctionExtInfo(CEE->getType()).getNoReturn()) {
+ QualType calleeType = CEE->getType();
+ if (calleeType == AC.getASTContext().BoundMemberTy) {
+ calleeType = Expr::findBoundMemberType(CEE);
+ assert(!calleeType.isNull() && "analyzing unresolved call?");
+ }
+ if (getFunctionExtInfo(calleeType).getNoReturn()) {
NoReturnEdge = true;
HasFakeEdge = true;
} else if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(CEE)) {
diff --git a/lib/Sema/DeclSpec.cpp b/lib/Sema/DeclSpec.cpp
index 0f20d10..5be16e7 100644
--- a/lib/Sema/DeclSpec.cpp
+++ b/lib/Sema/DeclSpec.cpp
@@ -309,6 +309,7 @@ const char *DeclSpec::getSpecifierName(DeclSpec::TST T) {
case DeclSpec::TST_typeofExpr: return "typeof";
case DeclSpec::TST_auto: return "auto";
case DeclSpec::TST_decltype: return "(decltype)";
+ case DeclSpec::TST_underlyingType: return "__underlying_type";
case DeclSpec::TST_unknown_anytype: return "__unknown_anytype";
case DeclSpec::TST_error: return "(error)";
}
diff --git a/lib/Sema/JumpDiagnostics.cpp b/lib/Sema/JumpDiagnostics.cpp
index 867d78f..ae154aa 100644
--- a/lib/Sema/JumpDiagnostics.cpp
+++ b/lib/Sema/JumpDiagnostics.cpp
@@ -15,6 +15,7 @@
#include "clang/Sema/SemaInternal.h"
#include "clang/AST/DeclCXX.h"
#include "clang/AST/Expr.h"
+#include "clang/AST/ExprCXX.h"
#include "clang/AST/StmtObjC.h"
#include "clang/AST/StmtCXX.h"
#include "llvm/ADT/BitVector.h"
@@ -126,18 +127,45 @@ static std::pair<unsigned,unsigned>
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();
+ if (!VD->hasLocalStorage())
+ return std::make_pair(InDiag, OutDiag);
+
+ ASTContext &Context = D->getASTContext();
+ QualType T = Context.getBaseElementType(VD->getType());
if (!T->isDependentType()) {
- 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;
+ // C++0x [stmt.dcl]p3:
+ // A program that jumps from a point where a variable with automatic
+ // storage duration is not in scope to a point where it is in scope
+ // is ill-formed unless the variable has scalar type, class type with
+ // a trivial default constructor and a trivial destructor, a
+ // cv-qualified version of one of these types, or an array of one of
+ // the preceding types and is declared without an initializer (8.5).
+ // Check whether this is a C++ class.
+ CXXRecordDecl *Record = T->getAsCXXRecordDecl();
+
+ if (const Expr *Init = VD->getInit()) {
+ bool CallsTrivialConstructor = false;
+ if (Record) {
+ // FIXME: With generalized initializer lists, this may
+ // classify "X x{};" as having no initializer.
+ if (const CXXConstructExpr *Construct
+ = dyn_cast<CXXConstructExpr>(Init))
+ if (const CXXConstructorDecl *Constructor
+ = Construct->getConstructor())
+ if ((Context.getLangOptions().CPlusPlus0x
+ ? Record->hasTrivialDefaultConstructor()
+ : Record->isPOD()) &&
+ Constructor->isDefaultConstructor())
+ CallsTrivialConstructor = true;
+ }
+
+ if (!CallsTrivialConstructor)
+ InDiag = diag::note_protected_by_variable_init;
+ }
+
+ // Note whether we have a class with a non-trivial destructor.
+ if (Record && !Record->hasTrivialDestructor())
+ OutDiag = diag::note_exits_dtor;
}
}
diff --git a/lib/Sema/Sema.cpp b/lib/Sema/Sema.cpp
index 7707fb1..8297b31 100644
--- a/lib/Sema/Sema.cpp
+++ b/lib/Sema/Sema.cpp
@@ -31,6 +31,7 @@
#include "clang/AST/DeclCXX.h"
#include "clang/AST/DeclObjC.h"
#include "clang/AST/Expr.h"
+#include "clang/AST/ExprCXX.h"
#include "clang/AST/StmtCXX.h"
#include "clang/Lex/Preprocessor.h"
#include "clang/Basic/PartialDiagnostic.h"
@@ -377,30 +378,22 @@ void Sema::ActOnEndOfTranslationUnit() {
}
}
- bool SomethingChanged;
- do {
- SomethingChanged = false;
-
- // If DefinedUsedVTables ends up marking any virtual member functions it
- // might lead to more pending template instantiations, which we then need
- // to instantiate.
- if (DefineUsedVTables())
- SomethingChanged = true;
-
- // C++: Perform implicit template instantiations.
- //
- // FIXME: When we perform these implicit instantiations, we do not
- // carefully keep track of the point of instantiation (C++ [temp.point]).
- // This means that name lookup that occurs within the template
- // instantiation will always happen at the end of the translation unit,
- // so it will find some names that should not be found. Although this is
- // common behavior for C++ compilers, it is technically wrong. In the
- // future, we either need to be able to filter the results of name lookup
- // or we need to perform template instantiations earlier.
- if (PerformPendingInstantiations())
- SomethingChanged = true;
-
- } while (SomethingChanged);
+ // If DefinedUsedVTables ends up marking any virtual member functions it
+ // might lead to more pending template instantiations, which we then need
+ // to instantiate.
+ DefineUsedVTables();
+
+ // C++: Perform implicit template instantiations.
+ //
+ // FIXME: When we perform these implicit instantiations, we do not
+ // carefully keep track of the point of instantiation (C++ [temp.point]).
+ // This means that name lookup that occurs within the template
+ // instantiation will always happen at the end of the translation unit,
+ // so it will find some names that should not be found. Although this is
+ // common behavior for C++ compilers, it is technically wrong. In the
+ // future, we either need to be able to filter the results of name lookup
+ // or we need to perform template instantiations earlier.
+ PerformPendingInstantiations();
}
// Remove file scoped decls that turned out to be used.
@@ -473,6 +466,12 @@ void Sema::ActOnEndOfTranslationUnit() {
}
+ if (LangOpts.CPlusPlus0x &&
+ Diags.getDiagnosticLevel(diag::warn_delegating_ctor_cycle,
+ SourceLocation())
+ != Diagnostic::Ignored)
+ CheckDelegatingCtorCycles();
+
// If there were errors, disable 'unused' warnings since they will mostly be
// noise.
if (!Diags.hasErrorOccurred()) {
@@ -570,9 +569,12 @@ Sema::SemaDiagnosticBuilder::~SemaDiagnosticBuilder() {
break;
case DiagnosticIDs::SFINAE_AccessControl:
- // Unless access checking is specifically called out as a SFINAE
- // error, report this diagnostic.
- if (!SemaRef.AccessCheckingSFINAE)
+ // Per C++ Core Issue 1170, access control is part of SFINAE.
+ // Additionally, the AccessCheckingSFINAE flag can be used to temporary
+ // make access control a part of SFINAE for the purposes of checking
+ // type traits.
+ if (!SemaRef.AccessCheckingSFINAE &&
+ !SemaRef.getLangOptions().CPlusPlus0x)
break;
case DiagnosticIDs::SFINAE_SubstitutionFailure:
@@ -763,3 +765,101 @@ void PrettyDeclStackTraceEntry::print(llvm::raw_ostream &OS) const {
OS << '\n';
}
+
+/// \brief Figure out if an expression could be turned into a call.
+///
+/// Use this when trying to recover from an error where the programmer may have
+/// written just the name of a function instead of actually calling it.
+///
+/// \param E - The expression to examine.
+/// \param ZeroArgCallReturnTy - If the expression can be turned into a call
+/// with no arguments, this parameter is set to the type returned by such a
+/// call; otherwise, it is set to an empty QualType.
+/// \param NonTemplateOverloads - If the expression is an overloaded function
+/// name, this parameter is populated with the decls of the various overloads.
+bool Sema::isExprCallable(const Expr &E, QualType &ZeroArgCallReturnTy,
+ UnresolvedSetImpl &NonTemplateOverloads) {
+ ZeroArgCallReturnTy = QualType();
+ NonTemplateOverloads.clear();
+ if (const OverloadExpr *Overloads = dyn_cast<OverloadExpr>(&E)) {
+ for (OverloadExpr::decls_iterator it = Overloads->decls_begin(),
+ DeclsEnd = Overloads->decls_end(); it != DeclsEnd; ++it) {
+ // Our overload set may include TemplateDecls, which we'll ignore for our
+ // present purpose.
+ if (const FunctionDecl *OverloadDecl = dyn_cast<FunctionDecl>(*it)) {
+ NonTemplateOverloads.addDecl(*it);
+ if (OverloadDecl->getMinRequiredArguments() == 0)
+ ZeroArgCallReturnTy = OverloadDecl->getResultType();
+ }
+ }
+ return true;
+ }
+
+ if (const DeclRefExpr *DeclRef = dyn_cast<DeclRefExpr>(&E)) {
+ if (const FunctionDecl *Fun = dyn_cast<FunctionDecl>(DeclRef->getDecl())) {
+ if (Fun->getMinRequiredArguments() == 0)
+ ZeroArgCallReturnTy = Fun->getResultType();
+ return true;
+ }
+ }
+
+ // We don't have an expression that's convenient to get a FunctionDecl from,
+ // but we can at least check if the type is "function of 0 arguments".
+ QualType ExprTy = E.getType();
+ const FunctionType *FunTy = NULL;
+ QualType PointeeTy = ExprTy->getPointeeType();
+ if (!PointeeTy.isNull())
+ FunTy = PointeeTy->getAs<FunctionType>();
+ if (!FunTy)
+ FunTy = ExprTy->getAs<FunctionType>();
+ if (!FunTy && ExprTy == Context.BoundMemberTy) {
+ // Look for the bound-member type. If it's still overloaded, give up,
+ // although we probably should have fallen into the OverloadExpr case above
+ // if we actually have an overloaded bound member.
+ QualType BoundMemberTy = Expr::findBoundMemberType(&E);
+ if (!BoundMemberTy.isNull())
+ FunTy = BoundMemberTy->castAs<FunctionType>();
+ }
+
+ if (const FunctionProtoType *FPT =
+ dyn_cast_or_null<FunctionProtoType>(FunTy)) {
+ if (FPT->getNumArgs() == 0)
+ ZeroArgCallReturnTy = FunTy->getResultType();
+ return true;
+ }
+ return false;
+}
+
+/// \brief Give notes for a set of overloads.
+///
+/// A companion to isExprCallable. In cases when the name that the programmer
+/// wrote was an overloaded function, we may be able to make some guesses about
+/// plausible overloads based on their return types; such guesses can be handed
+/// off to this method to be emitted as notes.
+///
+/// \param Overloads - The overloads to note.
+/// \param FinalNoteLoc - If we've suppressed printing some overloads due to
+/// -fshow-overloads=best, this is the location to attach to the note about too
+/// many candidates. Typically this will be the location of the original
+/// ill-formed expression.
+void Sema::NoteOverloads(const UnresolvedSetImpl &Overloads,
+ const SourceLocation FinalNoteLoc) {
+ int ShownOverloads = 0;
+ int SuppressedOverloads = 0;
+ for (UnresolvedSetImpl::iterator It = Overloads.begin(),
+ DeclsEnd = Overloads.end(); It != DeclsEnd; ++It) {
+ // FIXME: Magic number for max shown overloads stolen from
+ // OverloadCandidateSet::NoteCandidates.
+ if (ShownOverloads >= 4 &&
+ Diags.getShowOverloads() == Diagnostic::Ovl_Best) {
+ ++SuppressedOverloads;
+ continue;
+ }
+ Diag(cast<FunctionDecl>(*It)->getSourceRange().getBegin(),
+ diag::note_member_ref_possible_intended_overload);
+ ++ShownOverloads;
+ }
+ if (SuppressedOverloads)
+ Diag(FinalNoteLoc, diag::note_ovl_too_many_candidates)
+ << SuppressedOverloads;
+}
diff --git a/lib/Sema/SemaAccess.cpp b/lib/Sema/SemaAccess.cpp
index 411d424..a26737e 100644
--- a/lib/Sema/SemaAccess.cpp
+++ b/lib/Sema/SemaAccess.cpp
@@ -146,8 +146,10 @@ struct AccessTarget : public AccessedEntity {
MemberNonce _,
CXXRecordDecl *NamingClass,
DeclAccessPair FoundDecl,
- QualType BaseObjectType)
- : AccessedEntity(Context, Member, NamingClass, FoundDecl, BaseObjectType) {
+ QualType BaseObjectType,
+ bool IsUsingDecl = false)
+ : AccessedEntity(Context, Member, NamingClass, FoundDecl, BaseObjectType),
+ IsUsingDeclaration(IsUsingDecl) {
initialize();
}
@@ -216,6 +218,7 @@ private:
DeclaringClass = DeclaringClass->getCanonicalDecl();
}
+ bool IsUsingDeclaration : 1;
bool HasInstanceContext : 1;
mutable bool CalculatedInstanceContext : 1;
mutable const CXXRecordDecl *InstanceContext;
@@ -445,8 +448,8 @@ static AccessResult MatchesFriend(Sema &S,
continue;
// If the template names don't match, it can't be a dependent
- // match. This isn't true in C++0x because of template aliases.
- if (!S.LangOpts.CPlusPlus0x && CTD->getDeclName() != Friend->getDeclName())
+ // match.
+ if (CTD->getDeclName() != Friend->getDeclName())
continue;
// If the class's context can't instantiate to the friend's
@@ -1129,6 +1132,44 @@ static void DiagnoseBadAccess(Sema &S, SourceLocation Loc,
DiagnoseAccessPath(S, EC, Entity);
}
+/// MSVC has a bug where if during an using declaration name lookup,
+/// the declaration found is unaccessible (private) and that declaration
+/// was bring into scope via another using declaration whose target
+/// declaration is accessible (public) then no error is generated.
+/// Example:
+/// class A {
+/// public:
+/// int f();
+/// };
+/// class B : public A {
+/// private:
+/// using A::f;
+/// };
+/// class C : public B {
+/// private:
+/// using B::f;
+/// };
+///
+/// Here, B::f is private so this should fail in Standard C++, but
+/// because B::f refers to A::f which is public MSVC accepts it.
+static bool IsMicrosoftUsingDeclarationAccessBug(Sema& S,
+ SourceLocation AccessLoc,
+ AccessTarget &Entity) {
+ if (UsingShadowDecl *Shadow =
+ dyn_cast<UsingShadowDecl>(Entity.getTargetDecl())) {
+ const NamedDecl *OrigDecl = Entity.getTargetDecl()->getUnderlyingDecl();
+ if (Entity.getTargetDecl()->getAccess() == AS_private &&
+ (OrigDecl->getAccess() == AS_public ||
+ OrigDecl->getAccess() == AS_protected)) {
+ S.Diag(AccessLoc, diag::war_ms_using_declaration_inaccessible)
+ << Shadow->getUsingDecl()->getQualifiedNameAsString()
+ << OrigDecl->getQualifiedNameAsString();
+ return true;
+ }
+ }
+ return false;
+}
+
/// Determines whether the accessed entity is accessible. Public members
/// have been weeded out by this point.
static AccessResult IsAccessible(Sema &S,
@@ -1232,6 +1273,10 @@ static AccessResult CheckEffectiveAccess(Sema &S,
AccessTarget &Entity) {
assert(Entity.getAccess() != AS_public && "called for public access!");
+ if (S.getLangOptions().Microsoft &&
+ IsMicrosoftUsingDeclarationAccessBug(S, Loc, Entity))
+ return AR_accessible;
+
switch (IsAccessible(S, EC, Entity)) {
case AR_dependent:
DelayDependentAccess(S, EC, Loc, Entity);
@@ -1415,30 +1460,48 @@ Sema::AccessResult Sema::CheckConstructorAccess(SourceLocation UseLoc,
AccessTarget AccessEntity(Context, AccessTarget::Member, NamingClass,
DeclAccessPair::make(Constructor, Access),
QualType());
+ PartialDiagnostic PD(PDiag());
switch (Entity.getKind()) {
default:
- AccessEntity.setDiag(IsCopyBindingRefToTemp
- ? diag::ext_rvalue_to_reference_access_ctor
- : diag::err_access_ctor);
+ PD = PDiag(IsCopyBindingRefToTemp
+ ? diag::ext_rvalue_to_reference_access_ctor
+ : diag::err_access_ctor);
+
break;
case InitializedEntity::EK_Base:
- AccessEntity.setDiag(PDiag(diag::err_access_base)
- << Entity.isInheritedVirtualBase()
- << Entity.getBaseSpecifier()->getType()
- << getSpecialMember(Constructor));
+ PD = PDiag(diag::err_access_base_ctor);
+ PD << Entity.isInheritedVirtualBase()
+ << Entity.getBaseSpecifier()->getType() << getSpecialMember(Constructor);
break;
case InitializedEntity::EK_Member: {
const FieldDecl *Field = cast<FieldDecl>(Entity.getDecl());
- AccessEntity.setDiag(PDiag(diag::err_access_field)
- << Field->getType()
- << getSpecialMember(Constructor));
+ PD = PDiag(diag::err_access_field_ctor);
+ PD << Field->getType() << getSpecialMember(Constructor);
break;
}
}
+ return CheckConstructorAccess(UseLoc, Constructor, Access, PD);
+}
+
+/// Checks access to a constructor.
+Sema::AccessResult Sema::CheckConstructorAccess(SourceLocation UseLoc,
+ CXXConstructorDecl *Constructor,
+ AccessSpecifier Access,
+ PartialDiagnostic PD) {
+ if (!getLangOptions().AccessControl ||
+ Access == AS_public)
+ return AR_accessible;
+
+ CXXRecordDecl *NamingClass = Constructor->getParent();
+ AccessTarget AccessEntity(Context, AccessTarget::Member, NamingClass,
+ DeclAccessPair::make(Constructor, Access),
+ QualType());
+ AccessEntity.setDiag(PD);
+
return CheckAccess(*this, UseLoc, AccessEntity);
}
@@ -1465,7 +1528,8 @@ Sema::AccessResult Sema::CheckDirectMemberAccess(SourceLocation UseLoc,
Sema::AccessResult Sema::CheckAllocationAccess(SourceLocation OpLoc,
SourceRange PlacementRange,
CXXRecordDecl *NamingClass,
- DeclAccessPair Found) {
+ DeclAccessPair Found,
+ bool Diagnose) {
if (!getLangOptions().AccessControl ||
!NamingClass ||
Found.getAccess() == AS_public)
@@ -1473,8 +1537,9 @@ Sema::AccessResult Sema::CheckAllocationAccess(SourceLocation OpLoc,
AccessTarget Entity(Context, AccessTarget::Member, NamingClass, Found,
QualType());
- Entity.setDiag(diag::err_access)
- << PlacementRange;
+ if (Diagnose)
+ Entity.setDiag(diag::err_access)
+ << PlacementRange;
return CheckAccess(*this, OpLoc, Entity);
}
@@ -1573,9 +1638,8 @@ void Sema::CheckLookupAccess(const LookupResult &R) {
if (I.getAccess() != AS_public) {
AccessTarget Entity(Context, AccessedEntity::Member,
R.getNamingClass(), I.getPair(),
- R.getBaseObjectType());
+ R.getBaseObjectType(), R.isUsingDeclaration());
Entity.setDiag(diag::err_access);
-
CheckAccess(*this, R.getNameLoc(), Entity);
}
}
diff --git a/lib/Sema/SemaCXXCast.cpp b/lib/Sema/SemaCXXCast.cpp
index ed54f0f..e46ad5b 100644
--- a/lib/Sema/SemaCXXCast.cpp
+++ b/lib/Sema/SemaCXXCast.cpp
@@ -252,8 +252,7 @@ static bool tryDiagnoseOverloadedCast(Sema &S, CastType CT,
(CT == CT_CStyle || CT == CT_Functional));
InitializationSequence sequence(S, entity, initKind, &src, 1);
- assert(sequence.getKind() == InitializationSequence::FailedSequence &&
- "initialization succeeded on second try?");
+ assert(sequence.Failed() && "initialization succeeded on second try?");
switch (sequence.getFailureKind()) {
default: return false;
@@ -1195,8 +1194,7 @@ TryStaticImplicitCast(Sema &Self, ExprResult &SrcExpr, QualType DestType,
// On the other hand, if we're checking a C-style cast, we've still got
// the reinterpret_cast way.
- if (InitSeq.getKind() == InitializationSequence::FailedSequence &&
- (CStyle || !DestType->isReferenceType()))
+ if (InitSeq.Failed() && (CStyle || !DestType->isReferenceType()))
return TC_NotApplicable;
ExprResult Result
@@ -1288,6 +1286,62 @@ static TryCastResult TryConstCast(Sema &Self, Expr *SrcExpr, QualType DestType,
return TC_Success;
}
+// Checks for undefined behavior in reinterpret_cast.
+// The cases that is checked for is:
+// *reinterpret_cast<T*>(&a)
+// reinterpret_cast<T&>(a)
+// where accessing 'a' as type 'T' will result in undefined behavior.
+void Sema::CheckCompatibleReinterpretCast(QualType SrcType, QualType DestType,
+ bool IsDereference,
+ SourceRange Range) {
+ unsigned DiagID = IsDereference ?
+ diag::warn_pointer_indirection_from_incompatible_type :
+ diag::warn_undefined_reinterpret_cast;
+
+ if (Diags.getDiagnosticLevel(DiagID, Range.getBegin()) ==
+ Diagnostic::Ignored) {
+ return;
+ }
+
+ QualType SrcTy, DestTy;
+ if (IsDereference) {
+ if (!SrcType->getAs<PointerType>() || !DestType->getAs<PointerType>()) {
+ return;
+ }
+ SrcTy = SrcType->getPointeeType();
+ DestTy = DestType->getPointeeType();
+ } else {
+ if (!DestType->getAs<ReferenceType>()) {
+ return;
+ }
+ SrcTy = SrcType;
+ DestTy = DestType->getPointeeType();
+ }
+
+ // Cast is compatible if the types are the same.
+ if (Context.hasSameUnqualifiedType(DestTy, SrcTy)) {
+ return;
+ }
+ // or one of the types is a char or void type
+ if (DestTy->isAnyCharacterType() || DestTy->isVoidType() ||
+ SrcTy->isAnyCharacterType() || SrcTy->isVoidType()) {
+ return;
+ }
+ // or one of the types is a tag type.
+ if (SrcTy->getAs<TagType>() || DestTy->getAs<TagType>()) {
+ return;
+ }
+
+ // FIXME: Scoped enums?
+ if ((SrcTy->isUnsignedIntegerType() && DestTy->isSignedIntegerType()) ||
+ (SrcTy->isSignedIntegerType() && DestTy->isUnsignedIntegerType())) {
+ if (Context.getTypeSize(DestTy) == Context.getTypeSize(SrcTy)) {
+ return;
+ }
+ }
+
+ Diag(Range.getBegin(), DiagID) << SrcType << DestType << Range;
+}
static TryCastResult TryReinterpretCast(Sema &Self, ExprResult &SrcExpr,
QualType DestType, bool CStyle,
@@ -1324,6 +1378,11 @@ static TryCastResult TryReinterpretCast(Sema &Self, ExprResult &SrcExpr,
return TC_NotApplicable;
}
+ if (!CStyle) {
+ Self.CheckCompatibleReinterpretCast(SrcType, DestType,
+ /*isDereference=*/false, OpRange);
+ }
+
// C++ 5.2.10p10: [...] a reference cast reinterpret_cast<T&>(x) has the
// same effect as the conversion *reinterpret_cast<T*>(&x) with the
// built-in & and * operators.
@@ -1454,9 +1513,11 @@ static TryCastResult TryReinterpretCast(Sema &Self, ExprResult &SrcExpr,
if (DestType->isIntegralType(Self.Context)) {
assert(srcIsPtr && "One type must be a pointer");
// C++ 5.2.10p4: A pointer can be explicitly converted to any integral
- // type large enough to hold it.
- if (Self.Context.getTypeSize(SrcType) >
- Self.Context.getTypeSize(DestType)) {
+ // type large enough to hold it; except in Microsoft mode, where the
+ // integral type size doesn't matter.
+ if ((Self.Context.getTypeSize(SrcType) >
+ Self.Context.getTypeSize(DestType)) &&
+ !Self.getLangOptions().Microsoft) {
msg = diag::err_bad_reinterpret_cast_small_int;
return TC_Failed;
}
diff --git a/lib/Sema/SemaCXXScopeSpec.cpp b/lib/Sema/SemaCXXScopeSpec.cpp
index 7049f6b..61d9e93 100644
--- a/lib/Sema/SemaCXXScopeSpec.cpp
+++ b/lib/Sema/SemaCXXScopeSpec.cpp
@@ -94,9 +94,13 @@ DeclContext *Sema::computeDeclContext(const CXXScopeSpec &SS,
if (EnteringContext) {
const Type *NNSType = NNS->getAsType();
if (!NNSType) {
- // do nothing, fall out
- } else if (const TemplateSpecializationType *SpecType
- = NNSType->getAs<TemplateSpecializationType>()) {
+ return 0;
+ }
+
+ // Look through type alias templates, per C++0x [temp.dep.type]p1.
+ NNSType = Context.getCanonicalType(NNSType);
+ if (const TemplateSpecializationType *SpecType
+ = NNSType->getAs<TemplateSpecializationType>()) {
// We are entering the context of the nested name specifier, so try to
// match the nested name specifier to either a primary class template
// or a class template partial specialization.
@@ -382,7 +386,7 @@ bool Sema::BuildCXXNestedNameSpecifier(Scope *S,
isDependent = ObjectType->isDependentType();
} else if (SS.isSet()) {
// This nested-name-specifier occurs after another nested-name-specifier,
- // so long into the context associated with the prior nested-name-specifier.
+ // so look into the context associated with the prior nested-name-specifier.
LookupCtx = computeDeclContext(SS, EnteringContext);
isDependent = isDependentScopeSpecifier(SS);
Found.setContextRange(SS.getRange());
@@ -419,7 +423,7 @@ bool Sema::BuildCXXNestedNameSpecifier(Scope *S,
// class-name or namespace-name. [...]
//
// Qualified name lookup into a class will not find a namespace-name,
- // so we do not need to diagnoste that case specifically. However,
+ // so we do not need to diagnose that case specifically. However,
// this qualified name lookup may find nothing. In that case, perform
// unqualified name lookup in the given scope (if available) or
// reconstruct the result from when name lookup was performed at template
@@ -546,25 +550,33 @@ bool Sema::BuildCXXNestedNameSpecifier(Scope *S,
InjectedClassNameTypeLoc InjectedTL
= TLB.push<InjectedClassNameTypeLoc>(T);
InjectedTL.setNameLoc(IdentifierLoc);
- } else if (isa<RecordDecl>(SD)) {
+ } else if (isa<RecordType>(T)) {
RecordTypeLoc RecordTL = TLB.push<RecordTypeLoc>(T);
RecordTL.setNameLoc(IdentifierLoc);
- } else if (isa<TypedefNameDecl>(SD)) {
+ } else if (isa<TypedefType>(T)) {
TypedefTypeLoc TypedefTL = TLB.push<TypedefTypeLoc>(T);
TypedefTL.setNameLoc(IdentifierLoc);
- } else if (isa<EnumDecl>(SD)) {
+ } else if (isa<EnumType>(T)) {
EnumTypeLoc EnumTL = TLB.push<EnumTypeLoc>(T);
EnumTL.setNameLoc(IdentifierLoc);
- } else if (isa<TemplateTypeParmDecl>(SD)) {
+ } else if (isa<TemplateTypeParmType>(T)) {
TemplateTypeParmTypeLoc TemplateTypeTL
= TLB.push<TemplateTypeParmTypeLoc>(T);
TemplateTypeTL.setNameLoc(IdentifierLoc);
- } else {
- assert(isa<UnresolvedUsingTypenameDecl>(SD) &&
- "Unhandled TypeDecl node in nested-name-specifier");
+ } else if (isa<UnresolvedUsingType>(T)) {
UnresolvedUsingTypeLoc UnresolvedTL
= TLB.push<UnresolvedUsingTypeLoc>(T);
UnresolvedTL.setNameLoc(IdentifierLoc);
+ } else if (isa<SubstTemplateTypeParmType>(T)) {
+ SubstTemplateTypeParmTypeLoc TL
+ = TLB.push<SubstTemplateTypeParmTypeLoc>(T);
+ TL.setNameLoc(IdentifierLoc);
+ } else if (isa<SubstTemplateTypeParmPackType>(T)) {
+ SubstTemplateTypeParmPackTypeLoc TL
+ = TLB.push<SubstTemplateTypeParmPackTypeLoc>(T);
+ TL.setNameLoc(IdentifierLoc);
+ } else {
+ llvm_unreachable("Unhandled TypeDecl node in nested-name-specifier");
}
SS.Extend(Context, SourceLocation(), TLB.getTypeLocInContext(Context, T),
@@ -704,8 +716,13 @@ bool Sema::ActOnCXXNestedNameSpecifier(Scope *S,
if (T.isNull())
return true;
- // FIXME: Template aliases will need to check the resulting type to make
- // sure that it's either dependent or a tag type.
+ // Alias template specializations can produce types which are not valid
+ // nested name specifiers.
+ if (!T->isDependentType() && !T->getAs<TagType>()) {
+ Diag(TemplateNameLoc, diag::err_nested_name_spec_non_tag) << T;
+ NoteAllFoundTemplates(Template.get());
+ return true;
+ }
// Provide source-location information for the template specialization
// type.
diff --git a/lib/Sema/SemaChecking.cpp b/lib/Sema/SemaChecking.cpp
index dcfb7cc..05c257a 100644
--- a/lib/Sema/SemaChecking.cpp
+++ b/lib/Sema/SemaChecking.cpp
@@ -318,9 +318,13 @@ bool Sema::CheckFunctionCall(FunctionDecl *FDecl, CallExpr *TheCall) {
TheCall->getCallee()->getLocStart());
}
- // Memset handling
- if (FnInfo->isStr("memset"))
- CheckMemsetArguments(TheCall);
+ // Memset/memcpy/memmove handling
+ if (FDecl->getLinkage() == ExternalLinkage &&
+ (!getLangOptions().CPlusPlus || FDecl->isExternC())) {
+ if (FnInfo->isStr("memset") || FnInfo->isStr("memcpy") ||
+ FnInfo->isStr("memmove"))
+ CheckMemsetcpymoveArguments(TheCall, FnInfo);
+ }
return false;
}
@@ -1797,49 +1801,59 @@ void Sema::CheckFormatString(const StringLiteral *FExpr,
//===--- CHECK: Standard memory functions ---------------------------------===//
+/// \brief Determine whether the given type is a dynamic class type (e.g.,
+/// whether it has a vtable).
+static bool isDynamicClassType(QualType T) {
+ if (CXXRecordDecl *Record = T->getAsCXXRecordDecl())
+ if (CXXRecordDecl *Definition = Record->getDefinition())
+ if (Definition->isDynamicClass())
+ return true;
+
+ return false;
+}
+
/// \brief Check for dangerous or invalid arguments to memset().
///
-/// This issues warnings on known problematic or dangerous or unspecified
-/// arguments to the standard 'memset' function call.
+/// This issues warnings on known problematic, dangerous or unspecified
+/// arguments to the standard 'memset', 'memcpy', and 'memmove' function calls.
///
/// \param Call The call expression to diagnose.
-void Sema::CheckMemsetArguments(const CallExpr *Call) {
+void Sema::CheckMemsetcpymoveArguments(const CallExpr *Call,
+ const IdentifierInfo *FnName) {
// It is possible to have a non-standard definition of memset. Validate
// we have the proper number of arguments, and if not, abort further
// checking.
if (Call->getNumArgs() != 3)
return;
- const Expr *Dest = Call->getArg(0)->IgnoreParenImpCasts();
-
- // The type checking for this warning is moderately expensive, only do it
- // when enabled.
- if (getDiagnostics().getDiagnosticLevel(diag::warn_non_pod_memset,
- Dest->getExprLoc()) ==
- Diagnostic::Ignored)
- return;
-
- QualType DestTy = Dest->getType();
- if (const PointerType *DestPtrTy = DestTy->getAs<PointerType>()) {
- QualType PointeeTy = DestPtrTy->getPointeeType();
- if (PointeeTy->isVoidType())
- return;
-
- // Check the C++11 POD definition regardless of language mode; it is more
- // relaxed than earlier definitions and we don't want spurrious warnings.
- if (PointeeTy->isCXX11PODType())
- return;
-
- DiagRuntimeBehavior(
- Dest->getExprLoc(), Dest,
- PDiag(diag::warn_non_pod_memset)
- << PointeeTy << Call->getCallee()->getSourceRange());
+ unsigned LastArg = FnName->isStr("memset")? 1 : 2;
+ for (unsigned ArgIdx = 0; ArgIdx != LastArg; ++ArgIdx) {
+ const Expr *Dest = Call->getArg(ArgIdx)->IgnoreParenImpCasts();
+
+ QualType DestTy = Dest->getType();
+ if (const PointerType *DestPtrTy = DestTy->getAs<PointerType>()) {
+ QualType PointeeTy = DestPtrTy->getPointeeType();
+ if (PointeeTy->isVoidType())
+ continue;
+
+ // Always complain about dynamic classes.
+ if (isDynamicClassType(PointeeTy)) {
+ DiagRuntimeBehavior(
+ Dest->getExprLoc(), Dest,
+ PDiag(diag::warn_dyn_class_memaccess)
+ << ArgIdx << FnName << PointeeTy
+ << Call->getCallee()->getSourceRange());
+ } else {
+ continue;
+ }
- SourceRange ArgRange = Call->getArg(0)->getSourceRange();
- DiagRuntimeBehavior(
- Dest->getExprLoc(), Dest,
- PDiag(diag::note_non_pod_memset_silence)
- << FixItHint::CreateInsertion(ArgRange.getBegin(), "(void*)"));
+ SourceRange ArgRange = Call->getArg(0)->getSourceRange();
+ DiagRuntimeBehavior(
+ Dest->getExprLoc(), Dest,
+ PDiag(diag::note_bad_memaccess_silence)
+ << FixItHint::CreateInsertion(ArgRange.getBegin(), "(void*)"));
+ break;
+ }
}
}
@@ -2356,7 +2370,7 @@ IntRange GetValueRange(ASTContext &C, APValue &result, QualType Ty,
// the sign right on this one case. It would be nice if APValue
// preserved this.
assert(result.isLValue());
- return IntRange(MaxWidth, Ty->isUnsignedIntegerType());
+ return IntRange(MaxWidth, Ty->isUnsignedIntegerOrEnumerationType());
}
/// Pseudo-evaluate the given integer expression, estimating the
@@ -2530,7 +2544,8 @@ IntRange GetExprRange(ASTContext &C, Expr *E, unsigned MaxWidth) {
llvm::APSInt BitWidthAP = BitField->getBitWidth()->EvaluateAsInt(C);
unsigned BitWidth = BitWidthAP.getZExtValue();
- return IntRange(BitWidth, BitField->getType()->isUnsignedIntegerType());
+ return IntRange(BitWidth,
+ BitField->getType()->isUnsignedIntegerOrEnumerationType());
}
return IntRange::forValueOfType(C, E->getType());
@@ -2947,6 +2962,13 @@ void CheckImplicitConversion(Sema &S, Expr *E, QualType T,
if (!Source->isIntegerType() || !Target->isIntegerType())
return;
+ if ((E->isNullPointerConstant(S.Context, Expr::NPC_ValueDependentIsNotNull)
+ == Expr::NPCK_GNUNull) && Target->isIntegerType()) {
+ S.Diag(E->getExprLoc(), diag::warn_impcast_null_pointer_to_integer)
+ << E->getSourceRange() << clang::SourceRange(CC);
+ return;
+ }
+
IntRange SourceRange = GetExprRange(S.Context, E);
IntRange TargetRange = IntRange::forTargetOfCanonicalType(S.Context, Target);
diff --git a/lib/Sema/SemaCodeComplete.cpp b/lib/Sema/SemaCodeComplete.cpp
index cc8726d..e328eeb 100644
--- a/lib/Sema/SemaCodeComplete.cpp
+++ b/lib/Sema/SemaCodeComplete.cpp
@@ -2658,6 +2658,16 @@ CXCursorKind clang::getCursorKindForDecl(Decl *D) {
case Decl::UnresolvedUsingTypename:
return CXCursor_UsingDeclaration;
+ case Decl::ObjCPropertyImpl:
+ switch (cast<ObjCPropertyImplDecl>(D)->getPropertyImplementation()) {
+ case ObjCPropertyImplDecl::Dynamic:
+ return CXCursor_ObjCDynamicDecl;
+
+ case ObjCPropertyImplDecl::Synthesize:
+ return CXCursor_ObjCSynthesizeDecl;
+ }
+ break;
+
default:
if (TagDecl *TD = dyn_cast<TagDecl>(D)) {
switch (TD->getTagKind()) {
@@ -3078,6 +3088,7 @@ typedef llvm::SmallPtrSet<IdentifierInfo*, 16> AddedPropertiesSet;
static void AddObjCProperties(ObjCContainerDecl *Container,
bool AllowCategories,
+ bool AllowNullaryMethods,
DeclContext *CurContext,
AddedPropertiesSet &AddedProperties,
ResultBuilder &Results) {
@@ -3092,32 +3103,75 @@ static void AddObjCProperties(ObjCContainerDecl *Container,
Results.MaybeAddResult(Result(*P, 0), CurContext);
}
+ // Add nullary methods
+ if (AllowNullaryMethods) {
+ ASTContext &Context = Container->getASTContext();
+ for (ObjCContainerDecl::method_iterator M = Container->meth_begin(),
+ MEnd = Container->meth_end();
+ M != MEnd; ++M) {
+ if (M->getSelector().isUnarySelector())
+ if (IdentifierInfo *Name = M->getSelector().getIdentifierInfoForSlot(0))
+ if (AddedProperties.insert(Name)) {
+ CodeCompletionBuilder Builder(Results.getAllocator());
+ AddResultTypeChunk(Context, *M, Builder);
+ Builder.AddTypedTextChunk(
+ Results.getAllocator().CopyString(Name->getName()));
+
+ CXAvailabilityKind Availability = CXAvailability_Available;
+ switch (M->getAvailability()) {
+ case AR_Available:
+ case AR_NotYetIntroduced:
+ Availability = CXAvailability_Available;
+ break;
+
+ case AR_Deprecated:
+ Availability = CXAvailability_Deprecated;
+ break;
+
+ case AR_Unavailable:
+ Availability = CXAvailability_NotAvailable;
+ break;
+ }
+
+ Results.MaybeAddResult(Result(Builder.TakeString(),
+ CCP_MemberDeclaration + CCD_MethodAsProperty,
+ M->isInstanceMethod()
+ ? CXCursor_ObjCInstanceMethodDecl
+ : CXCursor_ObjCClassMethodDecl,
+ Availability),
+ CurContext);
+ }
+ }
+ }
+
+
// Add properties in referenced protocols.
if (ObjCProtocolDecl *Protocol = dyn_cast<ObjCProtocolDecl>(Container)) {
for (ObjCProtocolDecl::protocol_iterator P = Protocol->protocol_begin(),
PEnd = Protocol->protocol_end();
P != PEnd; ++P)
- AddObjCProperties(*P, AllowCategories, CurContext, AddedProperties,
- Results);
+ AddObjCProperties(*P, AllowCategories, AllowNullaryMethods, CurContext,
+ AddedProperties, Results);
} else if (ObjCInterfaceDecl *IFace = dyn_cast<ObjCInterfaceDecl>(Container)){
if (AllowCategories) {
// Look through categories.
for (ObjCCategoryDecl *Category = IFace->getCategoryList();
Category; Category = Category->getNextClassCategory())
- AddObjCProperties(Category, AllowCategories, CurContext,
- AddedProperties, Results);
+ AddObjCProperties(Category, AllowCategories, AllowNullaryMethods,
+ CurContext, AddedProperties, Results);
}
// Look through protocols.
for (ObjCInterfaceDecl::all_protocol_iterator
I = IFace->all_referenced_protocol_begin(),
E = IFace->all_referenced_protocol_end(); I != E; ++I)
- AddObjCProperties(*I, AllowCategories, CurContext, AddedProperties,
- Results);
+ AddObjCProperties(*I, AllowCategories, AllowNullaryMethods, CurContext,
+ AddedProperties, Results);
// Look in the superclass.
if (IFace->getSuperClass())
- AddObjCProperties(IFace->getSuperClass(), AllowCategories, CurContext,
+ AddObjCProperties(IFace->getSuperClass(), AllowCategories,
+ AllowNullaryMethods, CurContext,
AddedProperties, Results);
} else if (const ObjCCategoryDecl *Category
= dyn_cast<ObjCCategoryDecl>(Container)) {
@@ -3125,8 +3179,8 @@ static void AddObjCProperties(ObjCContainerDecl *Container,
for (ObjCCategoryDecl::protocol_iterator P = Category->protocol_begin(),
PEnd = Category->protocol_end();
P != PEnd; ++P)
- AddObjCProperties(*P, AllowCategories, CurContext, AddedProperties,
- Results);
+ AddObjCProperties(*P, AllowCategories, AllowNullaryMethods, CurContext,
+ AddedProperties, Results);
}
}
@@ -3192,14 +3246,16 @@ void Sema::CodeCompleteMemberReferenceExpr(Scope *S, ExprTy *BaseE,
const ObjCObjectPointerType *ObjCPtr
= BaseType->getAsObjCInterfacePointerType();
assert(ObjCPtr && "Non-NULL pointer guaranteed above!");
- AddObjCProperties(ObjCPtr->getInterfaceDecl(), true, CurContext,
+ AddObjCProperties(ObjCPtr->getInterfaceDecl(), true,
+ /*AllowNullaryMethods=*/true, CurContext,
AddedProperties, Results);
// Add properties from the protocols in a qualified interface.
for (ObjCObjectPointerType::qual_iterator I = ObjCPtr->qual_begin(),
E = ObjCPtr->qual_end();
I != E; ++I)
- AddObjCProperties(*I, true, CurContext, AddedProperties, Results);
+ AddObjCProperties(*I, true, /*AllowNullaryMethods=*/true, CurContext,
+ AddedProperties, Results);
} else if ((IsArrow && BaseType->isObjCObjectPointerType()) ||
(!IsArrow && BaseType->isObjCObjectType())) {
// Objective-C instance variable access.
@@ -4109,6 +4165,8 @@ void Sema::CodeCompleteObjCPropertyFlags(Scope *S, ObjCDeclSpec &ODS) {
Results.AddResult(CodeCompletionResult("copy"));
if (!ObjCPropertyFlagConflicts(Attributes, ObjCDeclSpec::DQ_PR_nonatomic))
Results.AddResult(CodeCompletionResult("nonatomic"));
+ if (!ObjCPropertyFlagConflicts(Attributes, ObjCDeclSpec::DQ_PR_atomic))
+ Results.AddResult(CodeCompletionResult("atomic"));
if (!ObjCPropertyFlagConflicts(Attributes, ObjCDeclSpec::DQ_PR_setter)) {
CodeCompletionBuilder Setter(Results.getAllocator());
Setter.AddTypedTextChunk("setter");
@@ -5334,11 +5392,13 @@ void Sema::CodeCompleteObjCPropertyDefinition(Scope *S, Decl *ObjCImpDecl) {
Results.EnterNewScope();
if (ObjCImplementationDecl *ClassImpl
= dyn_cast<ObjCImplementationDecl>(Container))
- AddObjCProperties(ClassImpl->getClassInterface(), false, CurContext,
+ AddObjCProperties(ClassImpl->getClassInterface(), false,
+ /*AllowNullaryMethods=*/false, CurContext,
AddedProperties, Results);
else
AddObjCProperties(cast<ObjCCategoryImplDecl>(Container)->getCategoryDecl(),
- false, CurContext, AddedProperties, Results);
+ false, /*AllowNullaryMethods=*/false, CurContext,
+ AddedProperties, Results);
Results.ExitScope();
HandleCodeCompleteResults(this, CodeCompleter,
@@ -5549,7 +5609,7 @@ static void AddObjCKeyValueCompletions(ObjCPropertyDecl *Property,
bool IsInstanceMethod,
QualType ReturnType,
ASTContext &Context,
- const KnownMethodsMap &KnownMethods,
+ VisitedSelectorSet &KnownSelectors,
ResultBuilder &Results) {
IdentifierInfo *PropName = Property->getIdentifier();
if (!PropName || PropName->getLength() == 0)
@@ -5595,7 +5655,7 @@ static void AddObjCKeyValueCompletions(ObjCPropertyDecl *Property,
// Add the normal accessor -(type)key.
if (IsInstanceMethod &&
- !KnownMethods.count(Selectors.getNullarySelector(PropName)) &&
+ KnownSelectors.insert(Selectors.getNullarySelector(PropName)) &&
ReturnTypeMatchesProperty && !Property->getGetterMethodDecl()) {
if (ReturnType.isNull())
AddObjCPassingTypeChunk(Property->getType(), Context, Builder);
@@ -5615,7 +5675,7 @@ static void AddObjCKeyValueCompletions(ObjCPropertyDecl *Property,
Property->getType()->isBooleanType())))) {
std::string SelectorName = (llvm::Twine("is") + UpperKey).str();
IdentifierInfo *SelectorId = &Context.Idents.get(SelectorName);
- if (!KnownMethods.count(Selectors.getNullarySelector(SelectorId))) {
+ if (KnownSelectors.insert(Selectors.getNullarySelector(SelectorId))) {
if (ReturnType.isNull()) {
Builder.AddChunk(CodeCompletionString::CK_LeftParen);
Builder.AddTextChunk("BOOL");
@@ -5634,7 +5694,7 @@ static void AddObjCKeyValueCompletions(ObjCPropertyDecl *Property,
!Property->getSetterMethodDecl()) {
std::string SelectorName = (llvm::Twine("set") + UpperKey).str();
IdentifierInfo *SelectorId = &Context.Idents.get(SelectorName);
- if (!KnownMethods.count(Selectors.getUnarySelector(SelectorId))) {
+ if (KnownSelectors.insert(Selectors.getUnarySelector(SelectorId))) {
if (ReturnType.isNull()) {
Builder.AddChunk(CodeCompletionString::CK_LeftParen);
Builder.AddTextChunk("void");
@@ -5685,7 +5745,7 @@ static void AddObjCKeyValueCompletions(ObjCPropertyDecl *Property,
(ReturnType.isNull() || ReturnType->isIntegerType())) {
std::string SelectorName = (llvm::Twine("countOf") + UpperKey).str();
IdentifierInfo *SelectorId = &Context.Idents.get(SelectorName);
- if (!KnownMethods.count(Selectors.getNullarySelector(SelectorId))) {
+ if (KnownSelectors.insert(Selectors.getNullarySelector(SelectorId))) {
if (ReturnType.isNull()) {
Builder.AddChunk(CodeCompletionString::CK_LeftParen);
Builder.AddTextChunk("NSUInteger");
@@ -5708,7 +5768,7 @@ static void AddObjCKeyValueCompletions(ObjCPropertyDecl *Property,
std::string SelectorName
= (llvm::Twine("objectIn") + UpperKey + "AtIndex").str();
IdentifierInfo *SelectorId = &Context.Idents.get(SelectorName);
- if (!KnownMethods.count(Selectors.getUnarySelector(SelectorId))) {
+ if (KnownSelectors.insert(Selectors.getUnarySelector(SelectorId))) {
if (ReturnType.isNull()) {
Builder.AddChunk(CodeCompletionString::CK_LeftParen);
Builder.AddTextChunk("id");
@@ -5735,7 +5795,7 @@ static void AddObjCKeyValueCompletions(ObjCPropertyDecl *Property,
std::string SelectorName
= (llvm::Twine(Property->getName()) + "AtIndexes").str();
IdentifierInfo *SelectorId = &Context.Idents.get(SelectorName);
- if (!KnownMethods.count(Selectors.getUnarySelector(SelectorId))) {
+ if (KnownSelectors.insert(Selectors.getUnarySelector(SelectorId))) {
if (ReturnType.isNull()) {
Builder.AddChunk(CodeCompletionString::CK_LeftParen);
Builder.AddTextChunk("NSArray *");
@@ -5760,7 +5820,7 @@ static void AddObjCKeyValueCompletions(ObjCPropertyDecl *Property,
&Context.Idents.get("range")
};
- if (!KnownMethods.count(Selectors.getSelector(2, SelectorIds))) {
+ if (KnownSelectors.insert(Selectors.getSelector(2, SelectorIds))) {
if (ReturnType.isNull()) {
Builder.AddChunk(CodeCompletionString::CK_LeftParen);
Builder.AddTextChunk("void");
@@ -5794,7 +5854,7 @@ static void AddObjCKeyValueCompletions(ObjCPropertyDecl *Property,
&Context.Idents.get(SelectorName)
};
- if (!KnownMethods.count(Selectors.getSelector(2, SelectorIds))) {
+ if (KnownSelectors.insert(Selectors.getSelector(2, SelectorIds))) {
if (ReturnType.isNull()) {
Builder.AddChunk(CodeCompletionString::CK_LeftParen);
Builder.AddTextChunk("void");
@@ -5826,7 +5886,7 @@ static void AddObjCKeyValueCompletions(ObjCPropertyDecl *Property,
&Context.Idents.get("atIndexes")
};
- if (!KnownMethods.count(Selectors.getSelector(2, SelectorIds))) {
+ if (KnownSelectors.insert(Selectors.getSelector(2, SelectorIds))) {
if (ReturnType.isNull()) {
Builder.AddChunk(CodeCompletionString::CK_LeftParen);
Builder.AddTextChunk("void");
@@ -5854,7 +5914,7 @@ static void AddObjCKeyValueCompletions(ObjCPropertyDecl *Property,
std::string SelectorName
= (llvm::Twine("removeObjectFrom") + UpperKey + "AtIndex").str();
IdentifierInfo *SelectorId = &Context.Idents.get(SelectorName);
- if (!KnownMethods.count(Selectors.getUnarySelector(SelectorId))) {
+ if (KnownSelectors.insert(Selectors.getUnarySelector(SelectorId))) {
if (ReturnType.isNull()) {
Builder.AddChunk(CodeCompletionString::CK_LeftParen);
Builder.AddTextChunk("void");
@@ -5876,7 +5936,7 @@ static void AddObjCKeyValueCompletions(ObjCPropertyDecl *Property,
std::string SelectorName
= (llvm::Twine("remove") + UpperKey + "AtIndexes").str();
IdentifierInfo *SelectorId = &Context.Idents.get(SelectorName);
- if (!KnownMethods.count(Selectors.getUnarySelector(SelectorId))) {
+ if (KnownSelectors.insert(Selectors.getUnarySelector(SelectorId))) {
if (ReturnType.isNull()) {
Builder.AddChunk(CodeCompletionString::CK_LeftParen);
Builder.AddTextChunk("void");
@@ -5902,7 +5962,7 @@ static void AddObjCKeyValueCompletions(ObjCPropertyDecl *Property,
&Context.Idents.get("withObject")
};
- if (!KnownMethods.count(Selectors.getSelector(2, SelectorIds))) {
+ if (KnownSelectors.insert(Selectors.getSelector(2, SelectorIds))) {
if (ReturnType.isNull()) {
Builder.AddChunk(CodeCompletionString::CK_LeftParen);
Builder.AddTextChunk("void");
@@ -5935,7 +5995,7 @@ static void AddObjCKeyValueCompletions(ObjCPropertyDecl *Property,
&Context.Idents.get(SelectorName2)
};
- if (!KnownMethods.count(Selectors.getSelector(2, SelectorIds))) {
+ if (KnownSelectors.insert(Selectors.getSelector(2, SelectorIds))) {
if (ReturnType.isNull()) {
Builder.AddChunk(CodeCompletionString::CK_LeftParen);
Builder.AddTextChunk("void");
@@ -5968,7 +6028,7 @@ static void AddObjCKeyValueCompletions(ObjCPropertyDecl *Property,
->getName() == "NSEnumerator"))) {
std::string SelectorName = (llvm::Twine("enumeratorOf") + UpperKey).str();
IdentifierInfo *SelectorId = &Context.Idents.get(SelectorName);
- if (!KnownMethods.count(Selectors.getNullarySelector(SelectorId))) {
+ if (KnownSelectors.insert(Selectors.getNullarySelector(SelectorId))) {
if (ReturnType.isNull()) {
Builder.AddChunk(CodeCompletionString::CK_LeftParen);
Builder.AddTextChunk("NSEnumerator *");
@@ -5986,7 +6046,7 @@ static void AddObjCKeyValueCompletions(ObjCPropertyDecl *Property,
(ReturnType.isNull() || ReturnType->isObjCObjectPointerType())) {
std::string SelectorName = (llvm::Twine("memberOf") + UpperKey).str();
IdentifierInfo *SelectorId = &Context.Idents.get(SelectorName);
- if (!KnownMethods.count(Selectors.getUnarySelector(SelectorId))) {
+ if (KnownSelectors.insert(Selectors.getUnarySelector(SelectorId))) {
if (ReturnType.isNull()) {
Builder.AddChunk(CodeCompletionString::CK_LeftParen);
Builder.AddPlaceholderChunk("object-type");
@@ -6016,7 +6076,7 @@ static void AddObjCKeyValueCompletions(ObjCPropertyDecl *Property,
std::string SelectorName
= (llvm::Twine("add") + UpperKey + llvm::Twine("Object")).str();
IdentifierInfo *SelectorId = &Context.Idents.get(SelectorName);
- if (!KnownMethods.count(Selectors.getUnarySelector(SelectorId))) {
+ if (KnownSelectors.insert(Selectors.getUnarySelector(SelectorId))) {
if (ReturnType.isNull()) {
Builder.AddChunk(CodeCompletionString::CK_LeftParen);
Builder.AddTextChunk("void");
@@ -6038,7 +6098,7 @@ static void AddObjCKeyValueCompletions(ObjCPropertyDecl *Property,
if (IsInstanceMethod && ReturnTypeMatchesVoid) {
std::string SelectorName = (llvm::Twine("add") + UpperKey).str();
IdentifierInfo *SelectorId = &Context.Idents.get(SelectorName);
- if (!KnownMethods.count(Selectors.getUnarySelector(SelectorId))) {
+ if (KnownSelectors.insert(Selectors.getUnarySelector(SelectorId))) {
if (ReturnType.isNull()) {
Builder.AddChunk(CodeCompletionString::CK_LeftParen);
Builder.AddTextChunk("void");
@@ -6060,7 +6120,7 @@ static void AddObjCKeyValueCompletions(ObjCPropertyDecl *Property,
std::string SelectorName
= (llvm::Twine("remove") + UpperKey + llvm::Twine("Object")).str();
IdentifierInfo *SelectorId = &Context.Idents.get(SelectorName);
- if (!KnownMethods.count(Selectors.getUnarySelector(SelectorId))) {
+ if (KnownSelectors.insert(Selectors.getUnarySelector(SelectorId))) {
if (ReturnType.isNull()) {
Builder.AddChunk(CodeCompletionString::CK_LeftParen);
Builder.AddTextChunk("void");
@@ -6082,7 +6142,7 @@ static void AddObjCKeyValueCompletions(ObjCPropertyDecl *Property,
if (IsInstanceMethod && ReturnTypeMatchesVoid) {
std::string SelectorName = (llvm::Twine("remove") + UpperKey).str();
IdentifierInfo *SelectorId = &Context.Idents.get(SelectorName);
- if (!KnownMethods.count(Selectors.getUnarySelector(SelectorId))) {
+ if (KnownSelectors.insert(Selectors.getUnarySelector(SelectorId))) {
if (ReturnType.isNull()) {
Builder.AddChunk(CodeCompletionString::CK_LeftParen);
Builder.AddTextChunk("void");
@@ -6103,7 +6163,7 @@ static void AddObjCKeyValueCompletions(ObjCPropertyDecl *Property,
if (IsInstanceMethod && ReturnTypeMatchesVoid) {
std::string SelectorName = (llvm::Twine("intersect") + UpperKey).str();
IdentifierInfo *SelectorId = &Context.Idents.get(SelectorName);
- if (!KnownMethods.count(Selectors.getUnarySelector(SelectorId))) {
+ if (KnownSelectors.insert(Selectors.getUnarySelector(SelectorId))) {
if (ReturnType.isNull()) {
Builder.AddChunk(CodeCompletionString::CK_LeftParen);
Builder.AddTextChunk("void");
@@ -6131,7 +6191,7 @@ static void AddObjCKeyValueCompletions(ObjCPropertyDecl *Property,
std::string SelectorName
= (llvm::Twine("keyPathsForValuesAffecting") + UpperKey).str();
IdentifierInfo *SelectorId = &Context.Idents.get(SelectorName);
- if (!KnownMethods.count(Selectors.getNullarySelector(SelectorId))) {
+ if (KnownSelectors.insert(Selectors.getNullarySelector(SelectorId))) {
if (ReturnType.isNull()) {
Builder.AddChunk(CodeCompletionString::CK_LeftParen);
Builder.AddTextChunk("NSSet *");
@@ -6140,7 +6200,28 @@ static void AddObjCKeyValueCompletions(ObjCPropertyDecl *Property,
Builder.AddTypedTextChunk(Allocator.CopyString(SelectorName));
Results.AddResult(Result(Builder.TakeString(), CCP_CodePattern,
- CXCursor_ObjCInstanceMethodDecl));
+ CXCursor_ObjCClassMethodDecl));
+ }
+ }
+
+ // + (BOOL)automaticallyNotifiesObserversForKey
+ if (!IsInstanceMethod &&
+ (ReturnType.isNull() ||
+ ReturnType->isIntegerType() ||
+ ReturnType->isBooleanType())) {
+ std::string SelectorName
+ = (llvm::Twine("automaticallyNotifiesObserversOf") + UpperKey).str();
+ IdentifierInfo *SelectorId = &Context.Idents.get(SelectorName);
+ if (KnownSelectors.insert(Selectors.getNullarySelector(SelectorId))) {
+ if (ReturnType.isNull()) {
+ Builder.AddChunk(CodeCompletionString::CK_LeftParen);
+ Builder.AddTextChunk("BOOL");
+ Builder.AddChunk(CodeCompletionString::CK_RightParen);
+ }
+
+ Builder.AddTypedTextChunk(Allocator.CopyString(SelectorName));
+ Results.AddResult(Result(Builder.TakeString(), CCP_CodePattern,
+ CXCursor_ObjCClassMethodDecl));
}
}
}
@@ -6271,6 +6352,13 @@ void Sema::CodeCompleteObjCMethodDecl(Scope *S,
llvm::SmallVector<ObjCContainerDecl *, 4> Containers;
Containers.push_back(SearchDecl);
+ VisitedSelectorSet KnownSelectors;
+ for (KnownMethodsMap::iterator M = KnownMethods.begin(),
+ MEnd = KnownMethods.end();
+ M != MEnd; ++M)
+ KnownSelectors.insert(M->first);
+
+
ObjCInterfaceDecl *IFace = dyn_cast<ObjCInterfaceDecl>(SearchDecl);
if (!IFace)
if (ObjCCategoryDecl *Category = dyn_cast<ObjCCategoryDecl>(SearchDecl))
@@ -6287,7 +6375,7 @@ void Sema::CodeCompleteObjCMethodDecl(Scope *S,
PEnd = Containers[I]->prop_end();
P != PEnd; ++P) {
AddObjCKeyValueCompletions(*P, IsInstanceMethod, ReturnType, Context,
- KnownMethods, Results);
+ KnownSelectors, Results);
}
}
}
diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp
index 7214988..9446c0e 100644
--- a/lib/Sema/SemaDecl.cpp
+++ b/lib/Sema/SemaDecl.cpp
@@ -891,19 +891,19 @@ static bool isOutOfScopePreviousDeclaration(NamedDecl *,
/// Filters out lookup results that don't fall within the given scope
/// as determined by isDeclInScope.
-static void FilterLookupForScope(Sema &SemaRef, LookupResult &R,
- DeclContext *Ctx, Scope *S,
- bool ConsiderLinkage,
- bool ExplicitInstantiationOrSpecialization) {
+void Sema::FilterLookupForScope(LookupResult &R,
+ DeclContext *Ctx, Scope *S,
+ bool ConsiderLinkage,
+ bool ExplicitInstantiationOrSpecialization) {
LookupResult::Filter F = R.makeFilter();
while (F.hasNext()) {
NamedDecl *D = F.next();
- if (SemaRef.isDeclInScope(D, Ctx, S, ExplicitInstantiationOrSpecialization))
+ if (isDeclInScope(D, Ctx, S, ExplicitInstantiationOrSpecialization))
continue;
if (ConsiderLinkage &&
- isOutOfScopePreviousDeclaration(D, Ctx, SemaRef.Context))
+ isOutOfScopePreviousDeclaration(D, Ctx, Context))
continue;
F.erase();
@@ -938,7 +938,7 @@ static void RemoveUsingDecls(LookupResult &R) {
static bool IsDisallowedCopyOrAssign(const CXXMethodDecl *D) {
// FIXME: Should check for private access too but access is set after we get
// the decl here.
- if (D->isThisDeclarationADefinition())
+ if (D->doesThisDeclarationHaveABody())
return false;
if (const CXXConstructorDecl *CD = dyn_cast<CXXConstructorDecl>(D))
@@ -973,10 +973,9 @@ bool Sema::ShouldWarnIfUnusedFileScopedDecl(const DeclaratorDecl *D) const {
return false;
}
- if (FD->isThisDeclarationADefinition() &&
+ if (FD->doesThisDeclarationHaveABody() &&
Context.DeclMustBeEmitted(FD))
return false;
-
} else if (const VarDecl *VD = dyn_cast<VarDecl>(D)) {
if (!VD->isFileVarDecl() ||
VD->getType().isConstant(Context) ||
@@ -1506,18 +1505,21 @@ struct GNUCompatibleParamWarning {
/// getSpecialMember - get the special member enum for a method.
Sema::CXXSpecialMember Sema::getSpecialMember(const CXXMethodDecl *MD) {
if (const CXXConstructorDecl *Ctor = dyn_cast<CXXConstructorDecl>(MD)) {
+ if (Ctor->isDefaultConstructor())
+ return Sema::CXXDefaultConstructor;
+
if (Ctor->isCopyConstructor())
return Sema::CXXCopyConstructor;
-
- return Sema::CXXConstructor;
- }
-
- if (isa<CXXDestructorDecl>(MD))
+
+ if (Ctor->isMoveConstructor())
+ return Sema::CXXMoveConstructor;
+ } else if (isa<CXXDestructorDecl>(MD)) {
return Sema::CXXDestructor;
-
- assert(MD->isCopyAssignmentOperator() &&
- "Must have copy assignment operator");
- return Sema::CXXCopyAssignment;
+ } else if (MD->isCopyAssignmentOperator()) {
+ return Sema::CXXCopyAssignment;
+ }
+
+ return Sema::CXXInvalid;
}
/// canRedefineFunction - checks if a function can be redefined. Currently,
@@ -1525,7 +1527,7 @@ Sema::CXXSpecialMember Sema::getSpecialMember(const CXXMethodDecl *MD) {
/// GNU89 mode.
static bool canRedefineFunction(const FunctionDecl *FD,
const LangOptions& LangOpts) {
- return (LangOpts.GNUMode && !LangOpts.C99 && !LangOpts.CPlusPlus &&
+ return (LangOpts.GNUInline && !LangOpts.CPlusPlus &&
FD->isInlineSpecified() &&
FD->getStorageClass() == SC_Extern);
}
@@ -1728,6 +1730,11 @@ bool Sema::MergeFunctionDecl(FunctionDecl *New, Decl *OldD) {
<< New << getSpecialMember(OldMethod);
return true;
}
+ } else if (OldMethod->isExplicitlyDefaulted()) {
+ Diag(NewMethod->getLocation(),
+ diag::err_definition_of_explicitly_defaulted_member)
+ << getSpecialMember(OldMethod);
+ return true;
}
}
@@ -1907,10 +1914,6 @@ bool Sema::MergeCompatibleFunctionDecls(FunctionDecl *New, FunctionDecl *Old) {
if (Old->isPure())
New->setPure();
- // Merge the "deleted" flag.
- if (Old->isDeleted())
- New->setDeleted();
-
// Merge attributes from the parameters. These can mismatch with K&R
// declarations.
if (New->getNumParams() == Old->getNumParams())
@@ -1933,7 +1936,9 @@ void Sema::mergeObjCMethodDecls(ObjCMethodDecl *newMethod,
for (ObjCMethodDecl::param_iterator oi = oldMethod->param_begin(),
ni = newMethod->param_begin(), ne = newMethod->param_end();
ni != ne; ++ni, ++oi)
- mergeParamDeclAttributes(*ni, *oi, Context);
+ mergeParamDeclAttributes(*ni, *oi, Context);
+
+ CheckObjCMethodOverride(newMethod, oldMethod, true);
}
/// MergeVarDeclTypes - We parsed a variable 'New' which has the same name and
@@ -2132,6 +2137,16 @@ void Sema::MergeVarDecl(VarDecl *New, LookupResult &Previous) {
/// no declarator (e.g. "struct foo;") is parsed.
Decl *Sema::ParsedFreeStandingDeclSpec(Scope *S, AccessSpecifier AS,
DeclSpec &DS) {
+ return ParsedFreeStandingDeclSpec(S, AS, DS,
+ MultiTemplateParamsArg(*this, 0, 0));
+}
+
+/// ParsedFreeStandingDeclSpec - This method is invoked when a declspec with
+/// no declarator (e.g. "struct foo;") is parsed. It also accopts template
+/// parameters to cope with template friend declarations.
+Decl *Sema::ParsedFreeStandingDeclSpec(Scope *S, AccessSpecifier AS,
+ DeclSpec &DS,
+ MultiTemplateParamsArg TemplateParams) {
Decl *TagD = 0;
TagDecl *Tag = 0;
if (DS.getTypeSpecType() == DeclSpec::TST_class ||
@@ -2163,7 +2178,7 @@ Decl *Sema::ParsedFreeStandingDeclSpec(Scope *S, AccessSpecifier AS,
// whatever routines created it handled the friendship aspect.
if (TagD && !Tag)
return 0;
- return ActOnFriendTypeDecl(S, DS, MultiTemplateParamsArg(*this, 0, 0));
+ return ActOnFriendTypeDecl(S, DS, TemplateParams);
}
// Track whether we warned about the fact that there aren't any
@@ -2484,6 +2499,24 @@ Decl *Sema::BuildAnonymousStructOrUnion(Scope *S, DeclSpec &DS,
PrevSpec, DiagID, getLangOptions());
}
+ // Ignore const/volatile/restrict qualifiers.
+ if (DS.getTypeQualifiers()) {
+ if (DS.getTypeQualifiers() & DeclSpec::TQ_const)
+ Diag(DS.getConstSpecLoc(), diag::ext_anonymous_struct_union_qualified)
+ << Record->isUnion() << 0
+ << FixItHint::CreateRemoval(DS.getConstSpecLoc());
+ if (DS.getTypeQualifiers() & DeclSpec::TQ_volatile)
+ Diag(DS.getVolatileSpecLoc(), diag::ext_anonymous_struct_union_qualified)
+ << Record->isUnion() << 1
+ << FixItHint::CreateRemoval(DS.getVolatileSpecLoc());
+ if (DS.getTypeQualifiers() & DeclSpec::TQ_restrict)
+ Diag(DS.getRestrictSpecLoc(), diag::ext_anonymous_struct_union_qualified)
+ << Record->isUnion() << 2
+ << FixItHint::CreateRemoval(DS.getRestrictSpecLoc());
+
+ DS.ClearTypeQualifiers();
+ }
+
// C++ [class.union]p2:
// The member-specification of an anonymous union shall only
// define non-static data members. [Note: nested types and
@@ -2502,7 +2535,12 @@ Decl *Sema::BuildAnonymousStructOrUnion(Scope *S, DeclSpec &DS,
Invalid = true;
}
- if (CheckNontrivialField(FD))
+ // C++ [class.union]p1
+ // An object of a class with a non-trivial constructor, a non-trivial
+ // copy constructor, a non-trivial destructor, or a non-trivial copy
+ // assignment operator cannot be a member of a union, nor can an
+ // array of such objects.
+ if (!getLangOptions().CPlusPlus0x && CheckNontrivialField(FD))
Invalid = true;
} else if ((*Mem)->isImplicit()) {
// Any implicit members are fine.
@@ -2572,7 +2610,8 @@ Decl *Sema::BuildAnonymousStructOrUnion(Scope *S, DeclSpec &DS,
/*IdentifierInfo=*/0,
Context.getTypeDeclType(Record),
TInfo,
- /*BitWidth=*/0, /*Mutable=*/false);
+ /*BitWidth=*/0, /*Mutable=*/false,
+ /*HasInit=*/false);
Anon->setAccess(AS);
if (getLangOptions().CPlusPlus)
FieldCollector->Add(cast<FieldDecl>(Anon));
@@ -2662,7 +2701,8 @@ Decl *Sema::BuildMicrosoftCAnonymousStruct(Scope *S, DeclSpec &DS,
/*IdentifierInfo=*/0,
Context.getTypeDeclType(Record),
TInfo,
- /*BitWidth=*/0, /*Mutable=*/false);
+ /*BitWidth=*/0, /*Mutable=*/false,
+ /*HasInit=*/false);
Anon->setImplicit();
// Add the anonymous struct object to the current context.
@@ -2829,7 +2869,8 @@ static bool RebuildDeclaratorInCurrentInstantiation(Sema &S, Declarator &D,
switch (DS.getTypeSpecType()) {
case DeclSpec::TST_typename:
case DeclSpec::TST_typeofType:
- case DeclSpec::TST_decltype: {
+ case DeclSpec::TST_decltype:
+ case DeclSpec::TST_underlyingType: {
// Grab the type from the parser.
TypeSourceInfo *TSI = 0;
QualType T = S.GetTypeFromParser(DS.getRepAsType(), &TSI);
@@ -2883,8 +2924,10 @@ static bool RebuildDeclaratorInCurrentInstantiation(Sema &S, Declarator &D,
return false;
}
-Decl *Sema::ActOnDeclarator(Scope *S, Declarator &D) {
- return HandleDeclarator(S, D, MultiTemplateParamsArg(*this), false);
+Decl *Sema::ActOnDeclarator(Scope *S, Declarator &D,
+ bool IsFunctionDefinition) {
+ return HandleDeclarator(S, D, MultiTemplateParamsArg(*this),
+ IsFunctionDefinition);
}
/// DiagnoseClassNameShadow - Implement C++ [class.mem]p13:
@@ -2952,7 +2995,6 @@ Decl *Sema::HandleDeclarator(Scope *S, Declarator &D,
<< D.getCXXScopeSpec().getRange();
return 0;
}
-
bool IsDependentContext = DC->isDependentContext();
if (!IsDependentContext &&
@@ -3294,15 +3336,13 @@ Sema::ActOnTypedefDeclarator(Scope* S, Declarator& D, DeclContext* DC,
// Handle attributes prior to checking for duplicates in MergeVarDecl
ProcessDeclAttributes(S, NewTD, D);
+ CheckTypedefForVariablyModifiedType(S, NewTD);
+
return ActOnTypedefNameDecl(S, DC, NewTD, Previous, Redeclaration);
}
-/// ActOnTypedefNameDecl - Perform semantic checking for a declaration which
-/// declares a typedef-name, either using the 'typedef' type specifier or via
-/// a C++0x [dcl.typedef]p2 alias-declaration: 'using T = A;'.
-NamedDecl*
-Sema::ActOnTypedefNameDecl(Scope *S, DeclContext *DC, TypedefNameDecl *NewTD,
- LookupResult &Previous, bool &Redeclaration) {
+void
+Sema::CheckTypedefForVariablyModifiedType(Scope *S, TypedefNameDecl *NewTD) {
// C99 6.7.7p2: If a typedef name specifies a variably modified type
// then it shall have block scope.
// Note that variably modified types must be fixed before merging the decl so
@@ -3333,10 +3373,18 @@ Sema::ActOnTypedefNameDecl(Scope *S, DeclContext *DC, TypedefNameDecl *NewTD,
}
}
}
+}
+
+/// ActOnTypedefNameDecl - Perform semantic checking for a declaration which
+/// declares a typedef-name, either using the 'typedef' type specifier or via
+/// a C++0x [dcl.typedef]p2 alias-declaration: 'using T = A;'.
+NamedDecl*
+Sema::ActOnTypedefNameDecl(Scope *S, DeclContext *DC, TypedefNameDecl *NewTD,
+ LookupResult &Previous, bool &Redeclaration) {
// Merge the decl with the existing one if appropriate. If the decl is
// in an outer scope, it isn't the same thing.
- FilterLookupForScope(*this, Previous, DC, S, /*ConsiderLinkage*/ false,
+ FilterLookupForScope(Previous, DC, S, /*ConsiderLinkage*/ false,
/*ExplicitInstantiationOrSpecialization=*/false);
if (!Previous.empty()) {
Redeclaration = true;
@@ -3518,7 +3566,8 @@ Sema::ActOnVariableDeclarator(Scope *S, Declarator &D, DeclContext *DC,
bool Invalid = false;
if (TemplateParameterList *TemplateParams
= MatchTemplateParametersToScopeSpecifier(
- D.getDeclSpec().getSourceRange().getBegin(),
+ D.getDeclSpec().getSourceRange().getBegin(),
+ D.getIdentifierLoc(),
D.getCXXScopeSpec(),
TemplateParamLists.get(),
TemplateParamLists.size(),
@@ -3540,7 +3589,6 @@ Sema::ActOnVariableDeclarator(Scope *S, Declarator &D, DeclContext *DC,
<< II
<< SourceRange(TemplateParams->getTemplateLoc(),
TemplateParams->getRAngleLoc());
- isExplicitSpecialization = true;
}
}
@@ -3615,7 +3663,7 @@ Sema::ActOnVariableDeclarator(Scope *S, Declarator &D, DeclContext *DC,
// Don't consider existing declarations that are in a different
// scope and are out-of-semantic-context declarations (if the new
// declaration has linkage).
- FilterLookupForScope(*this, Previous, DC, S, NewVD->hasLinkage(),
+ FilterLookupForScope(Previous, DC, S, NewVD->hasLinkage(),
isExplicitSpecialization);
if (!getLangOptions().CPlusPlus)
@@ -3806,8 +3854,12 @@ void Sema::CheckVariableDeclaration(VarDecl *NewVD,
}
if (NewVD->hasLocalStorage() && T.isObjCGCWeak()
- && !NewVD->hasAttr<BlocksAttr>())
- Diag(NewVD->getLocation(), diag::warn_attribute_weak_on_local);
+ && !NewVD->hasAttr<BlocksAttr>()) {
+ if (getLangOptions().getGCMode() != LangOptions::NonGC)
+ Diag(NewVD->getLocation(), diag::warn_gc_attribute_weak_on_local);
+ else
+ Diag(NewVD->getLocation(), diag::warn_attribute_weak_on_local);
+ }
bool isVM = T->isVariablyModifiedType();
if (isVM || NewVD->hasAttr<CleanupAttr>() ||
@@ -4062,7 +4114,7 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC,
// Set the lexical context.
NewFD->setLexicalDeclContext(CurContext);
// Filter out previous declarations that don't match the scope.
- FilterLookupForScope(*this, Previous, DC, S, NewFD->hasLinkage(),
+ FilterLookupForScope(Previous, DC, S, NewFD->hasLinkage(),
/*ExplicitInstantiationOrSpecialization=*/false);
} else {
isFriend = D.getDeclSpec().isFriendSpecified();
@@ -4088,24 +4140,38 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC,
R = CheckConstructorDeclarator(D, R, SC);
// Create the new declaration
- NewFD = CXXConstructorDecl::Create(Context,
+ CXXConstructorDecl *NewCD = CXXConstructorDecl::Create(
+ Context,
cast<CXXRecordDecl>(DC),
D.getSourceRange().getBegin(),
NameInfo, R, TInfo,
isExplicit, isInline,
/*isImplicitlyDeclared=*/false);
+
+ NewFD = NewCD;
} else if (Name.getNameKind() == DeclarationName::CXXDestructorName) {
// This is a C++ destructor declaration.
if (DC->isRecord()) {
R = CheckDestructorDeclarator(D, R, SC);
+ CXXRecordDecl *Record = cast<CXXRecordDecl>(DC);
- NewFD = CXXDestructorDecl::Create(Context,
- cast<CXXRecordDecl>(DC),
+ CXXDestructorDecl *NewDD = CXXDestructorDecl::Create(Context, Record,
D.getSourceRange().getBegin(),
NameInfo, R, TInfo,
isInline,
/*isImplicitlyDeclared=*/false);
+ NewFD = NewDD;
isVirtualOkay = true;
+
+ // If the class is complete, then we now create the implicit exception
+ // specification. If the class is incomplete or dependent, we can't do
+ // it yet.
+ if (getLangOptions().CPlusPlus0x && !Record->isDependentType() &&
+ Record->getDefinition() && !Record->isBeingDefined() &&
+ R->getAs<FunctionProtoType>()->getExceptionSpecType() == EST_None) {
+ AdjustDestructorExceptionSpec(Record, NewDD);
+ }
+
} else {
Diag(D.getIdentifierLoc(), diag::err_destructor_not_member);
@@ -4162,11 +4228,13 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC,
isStatic = true;
// This is a C++ method declaration.
- NewFD = CXXMethodDecl::Create(Context, cast<CXXRecordDecl>(DC),
- D.getSourceRange().getBegin(),
- NameInfo, R, TInfo,
- isStatic, SCAsWritten, isInline,
- SourceLocation());
+ CXXMethodDecl *NewMD = CXXMethodDecl::Create(
+ Context, cast<CXXRecordDecl>(DC),
+ D.getSourceRange().getBegin(),
+ NameInfo, R, TInfo,
+ isStatic, SCAsWritten, isInline,
+ SourceLocation());
+ NewFD = NewMD;
isVirtualOkay = !isStatic;
} else {
@@ -4202,6 +4270,7 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC,
if (TemplateParameterList *TemplateParams
= MatchTemplateParametersToScopeSpecifier(
D.getDeclSpec().getSourceRange().getBegin(),
+ D.getIdentifierLoc(),
D.getCXXScopeSpec(),
TemplateParamLists.get(),
TemplateParamLists.size(),
@@ -4339,7 +4408,7 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC,
}
// Filter out previous declarations that don't match the scope.
- FilterLookupForScope(*this, Previous, DC, S, NewFD->hasLinkage(),
+ FilterLookupForScope(Previous, DC, S, NewFD->hasLinkage(),
isExplicitSpecialization ||
isFunctionTemplateSpecialization);
@@ -4406,6 +4475,9 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC,
bool IsTypeAlias = false;
if (const TypedefType *TT = Param->getType()->getAs<TypedefType>())
IsTypeAlias = isa<TypeAliasDecl>(TT->getDecl());
+ else if (const TemplateSpecializationType *TST =
+ Param->getType()->getAs<TemplateSpecializationType>())
+ IsTypeAlias = TST->isTypeAlias();
Diag(Param->getLocation(), diag::err_param_typedef_of_void)
<< IsTypeAlias;
}
@@ -4452,8 +4524,8 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC,
if (!getLangOptions().CPlusPlus) {
// Perform semantic checking on the function declaration.
- bool isExplctSpecialization=false;
- CheckFunctionDeclaration(S, NewFD, Previous, isExplctSpecialization,
+ bool isExplicitSpecialization=false;
+ CheckFunctionDeclaration(S, NewFD, Previous, isExplicitSpecialization,
Redeclaration);
assert((NewFD->isInvalidDecl() || !Redeclaration ||
Previous.getResultKind() != LookupResult::FoundOverloaded) &&
@@ -4476,7 +4548,9 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC,
HasExplicitTemplateArgs = true;
- if (FunctionTemplate) {
+ if (NewFD->isInvalidDecl()) {
+ HasExplicitTemplateArgs = false;
+ } else if (FunctionTemplate) {
// Function template with explicit template arguments.
Diag(D.getIdentifierLoc(), diag::err_function_template_partial_spec)
<< SourceRange(TemplateId->LAngleLoc, TemplateId->RAngleLoc);
@@ -4532,6 +4606,16 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC,
(HasExplicitTemplateArgs ? &TemplateArgs : 0),
Previous))
NewFD->setInvalidDecl();
+
+ // C++ [dcl.stc]p1:
+ // A storage-class-specifier shall not be specified in an explicit
+ // specialization (14.7.3)
+ if (SC != SC_None) {
+ Diag(NewFD->getLocation(),
+ diag::err_explicit_specialization_storage_class)
+ << FixItHint::CreateRemoval(D.getDeclSpec().getStorageClassSpecLoc());
+ }
+
} else if (isExplicitSpecialization && isa<CXXMethodDecl>(NewFD)) {
if (CheckMemberSpecialization(NewFD, Previous))
NewFD->setInvalidDecl();
@@ -4647,8 +4731,8 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC,
<< D.getCXXScopeSpec().getRange();
}
}
-
-
+
+
// Handle attributes. We need to have merged decls when handling attributes
// (for example to check for conflicts, etc).
// FIXME: This needs to happen before we merge declarations. Then,
@@ -4661,7 +4745,7 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC,
if (Redeclaration && Previous.isSingleResult()) {
const FunctionDecl *Def;
FunctionDecl *PrevFD = dyn_cast<FunctionDecl>(Previous.getFoundDecl());
- if (PrevFD && PrevFD->hasBody(Def) && D.hasAttributes()) {
+ if (PrevFD && PrevFD->isDefined(Def) && D.hasAttributes()) {
Diag(NewFD->getLocation(), diag::warn_attribute_precede_definition);
Diag(Def->getLocation(), diag::note_previous_definition);
}
@@ -5076,9 +5160,11 @@ namespace {
if (OrigDecl != ReferenceDecl) return;
LookupResult Result(S, DRE->getNameInfo(), Sema::LookupOrdinaryName,
Sema::NotForRedeclaration);
- S.Diag(SubExpr->getLocStart(), diag::warn_uninit_self_reference_in_init)
- << Result.getLookupName() << OrigDecl->getLocation()
- << SubExpr->getSourceRange();
+ S.DiagRuntimeBehavior(SubExpr->getLocStart(), SubExpr,
+ S.PDiag(diag::warn_uninit_self_reference_in_init)
+ << Result.getLookupName()
+ << OrigDecl->getLocation()
+ << SubExpr->getSourceRange());
}
};
}
@@ -5553,40 +5639,53 @@ void Sema::ActOnUninitializedDecl(Decl *RealDecl,
return;
}
- const RecordType *Record
- = Context.getBaseElementType(Type)->getAs<RecordType>();
- if (Record && getLangOptions().CPlusPlus &&
- cast<CXXRecordDecl>(Record->getDecl())->isPOD()) {
- // C++03 [dcl.init]p9:
- // If no initializer is specified for an object, and the
- // object is of (possibly cv-qualified) non-POD class type (or
- // array thereof), the object shall be default-initialized; if
- // the object is of const-qualified type, the underlying class
- // type shall have a user-declared default
- // constructor. Otherwise, if no initializer is specified for
- // a non- static object, the object and its subobjects, if
- // any, have an indeterminate initial value); if the object
- // or any of its subobjects are of const-qualified type, the
- // program is ill-formed.
- } else {
- // Check for jumps past the implicit initializer. C++0x
- // clarifies that this applies to a "variable with automatic
- // storage duration", not a "local variable".
- if (getLangOptions().CPlusPlus && Var->hasLocalStorage())
- getCurFunction()->setHasBranchProtectedScope();
-
- InitializedEntity Entity = InitializedEntity::InitializeVariable(Var);
- InitializationKind Kind
- = InitializationKind::CreateDefault(Var->getLocation());
-
- InitializationSequence InitSeq(*this, Entity, Kind, 0, 0);
- ExprResult Init = InitSeq.Perform(*this, Entity, Kind,
- MultiExprArg(*this, 0, 0));
- if (Init.isInvalid())
- Var->setInvalidDecl();
- else if (Init.get())
- Var->setInit(MaybeCreateExprWithCleanups(Init.get()));
+ // Check for jumps past the implicit initializer. C++0x
+ // clarifies that this applies to a "variable with automatic
+ // storage duration", not a "local variable".
+ // C++0x [stmt.dcl]p3
+ // A program that jumps from a point where a variable with automatic
+ // storage duration is not in scope to a point where it is in scope is
+ // ill-formed unless the variable has scalar type, class type with a
+ // trivial default constructor and a trivial destructor, a cv-qualified
+ // version of one of these types, or an array of one of the preceding
+ // types and is declared without an initializer.
+ if (getLangOptions().CPlusPlus && Var->hasLocalStorage()) {
+ if (const RecordType *Record
+ = Context.getBaseElementType(Type)->getAs<RecordType>()) {
+ CXXRecordDecl *CXXRecord = cast<CXXRecordDecl>(Record->getDecl());
+ if ((!getLangOptions().CPlusPlus0x && !CXXRecord->isPOD()) ||
+ (getLangOptions().CPlusPlus0x &&
+ (!CXXRecord->hasTrivialDefaultConstructor() ||
+ !CXXRecord->hasTrivialDestructor())))
+ getCurFunction()->setHasBranchProtectedScope();
+ }
}
+
+ // C++03 [dcl.init]p9:
+ // If no initializer is specified for an object, and the
+ // object is of (possibly cv-qualified) non-POD class type (or
+ // array thereof), the object shall be default-initialized; if
+ // the object is of const-qualified type, the underlying class
+ // type shall have a user-declared default
+ // constructor. Otherwise, if no initializer is specified for
+ // a non- static object, the object and its subobjects, if
+ // any, have an indeterminate initial value); if the object
+ // or any of its subobjects are of const-qualified type, the
+ // program is ill-formed.
+ // C++0x [dcl.init]p11:
+ // If no initializer is specified for an object, the object is
+ // default-initialized; [...].
+ InitializedEntity Entity = InitializedEntity::InitializeVariable(Var);
+ InitializationKind Kind
+ = InitializationKind::CreateDefault(Var->getLocation());
+
+ InitializationSequence InitSeq(*this, Entity, Kind, 0, 0);
+ ExprResult Init = InitSeq.Perform(*this, Entity, Kind,
+ MultiExprArg(*this, 0, 0));
+ if (Init.isInvalid())
+ Var->setInvalidDecl();
+ else if (Init.get())
+ Var->setInit(MaybeCreateExprWithCleanups(Init.get()));
CheckCompleteVariableDeclaration(Var);
}
@@ -6056,7 +6155,7 @@ void Sema::CheckForFunctionRedefinition(FunctionDecl *FD) {
// Don't complain if we're in GNU89 mode and the previous definition
// was an extern inline function.
const FunctionDecl *Definition;
- if (FD->hasBody(Definition) &&
+ if (FD->isDefined(Definition) &&
!canRedefineFunction(Definition, getLangOptions())) {
if (getLangOptions().GNUMode && Definition->isInlineSpecified() &&
Definition->getStorageClass() == SC_Extern)
@@ -6221,6 +6320,11 @@ Decl *Sema::ActOnFinishFunctionBody(Decl *dcl, Stmt *Body,
WP.disableCheckFallThrough();
}
+ // MSVC permits the use of pure specifier (=0) on function definition,
+ // defined at class scope, warn about this non standard construct.
+ if (getLangOptions().Microsoft && FD->isPure())
+ Diag(FD->getLocation(), diag::warn_pure_function_definition);
+
if (!FD->isInvalidDecl()) {
DiagnoseUnusedParameters(FD->param_begin(), FD->param_end());
DiagnoseSizeOfParametersAndReturnValue(FD->param_begin(), FD->param_end(),
@@ -6499,7 +6603,7 @@ 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,
- TagTypeKind NewTag,
+ TagTypeKind NewTag, bool isDefinition,
SourceLocation NewTagLoc,
const IdentifierInfo &Name) {
// C++ [dcl.type.elab]p3:
@@ -6516,8 +6620,9 @@ bool Sema::isAcceptableTagRedeclaration(const TagDecl *Previous,
// struct class-key shall be used to refer to a class (clause 9)
// declared using the class or struct class-key.
TagTypeKind OldTag = Previous->getTagKind();
- if (OldTag == NewTag)
- return true;
+ if (!isDefinition || (NewTag != TTK_Class && NewTag != TTK_Struct))
+ if (OldTag == NewTag)
+ return true;
if ((OldTag == TTK_Struct || OldTag == TTK_Class) &&
(NewTag == TTK_Struct || NewTag == TTK_Class)) {
@@ -6526,12 +6631,63 @@ bool Sema::isAcceptableTagRedeclaration(const TagDecl *Previous,
if (const CXXRecordDecl *Record = dyn_cast<CXXRecordDecl>(Previous))
isTemplate = Record->getDescribedClassTemplate();
+ if (!ActiveTemplateInstantiations.empty()) {
+ // In a template instantiation, do not offer fix-its for tag mismatches
+ // since they usually mess up the template instead of fixing the problem.
+ Diag(NewTagLoc, diag::warn_struct_class_tag_mismatch)
+ << (NewTag == TTK_Class) << isTemplate << &Name;
+ return true;
+ }
+
+ if (isDefinition) {
+ // On definitions, check previous tags and issue a fix-it for each
+ // one that doesn't match the current tag.
+ if (Previous->getDefinition()) {
+ // Don't suggest fix-its for redefinitions.
+ return true;
+ }
+
+ bool previousMismatch = false;
+ for (TagDecl::redecl_iterator I(Previous->redecls_begin()),
+ E(Previous->redecls_end()); I != E; ++I) {
+ if (I->getTagKind() != NewTag) {
+ if (!previousMismatch) {
+ previousMismatch = true;
+ Diag(NewTagLoc, diag::warn_struct_class_previous_tag_mismatch)
+ << (NewTag == TTK_Class) << isTemplate << &Name;
+ }
+ Diag(I->getInnerLocStart(), diag::note_struct_class_suggestion)
+ << (NewTag == TTK_Class)
+ << FixItHint::CreateReplacement(I->getInnerLocStart(),
+ NewTag == TTK_Class?
+ "class" : "struct");
+ }
+ }
+ return true;
+ }
+
+ // Check for a previous definition. If current tag and definition
+ // are same type, do nothing. If no definition, but disagree with
+ // with previous tag type, give a warning, but no fix-it.
+ const TagDecl *Redecl = Previous->getDefinition() ?
+ Previous->getDefinition() : Previous;
+ if (Redecl->getTagKind() == NewTag) {
+ return true;
+ }
+
Diag(NewTagLoc, diag::warn_struct_class_tag_mismatch)
<< (NewTag == TTK_Class)
- << isTemplate << &Name
- << FixItHint::CreateReplacement(SourceRange(NewTagLoc),
- OldTag == TTK_Class? "class" : "struct");
- Diag(Previous->getLocation(), diag::note_previous_use);
+ << isTemplate << &Name;
+ Diag(Redecl->getLocation(), diag::note_previous_use);
+
+ // If there is a previous defintion, suggest a fix-it.
+ if (Previous->getDefinition()) {
+ Diag(NewTagLoc, diag::note_struct_class_suggestion)
+ << (Redecl->getTagKind() == TTK_Class)
+ << FixItHint::CreateReplacement(SourceRange(NewTagLoc),
+ Redecl->getTagKind() == TTK_Class? "class" : "struct");
+ }
+
return true;
}
return false;
@@ -6567,7 +6723,7 @@ Decl *Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK,
if (TemplateParameterLists.size() > 0 ||
(SS.isNotEmpty() && TUK != TUK_Reference)) {
if (TemplateParameterList *TemplateParams
- = MatchTemplateParametersToScopeSpecifier(KWLoc, SS,
+ = MatchTemplateParametersToScopeSpecifier(KWLoc, NameLoc, SS,
TemplateParameterLists.get(),
TemplateParameterLists.size(),
TUK == TUK_Friend,
@@ -6705,6 +6861,17 @@ Decl *Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK,
// shouldn't be diagnosing.
LookupName(Previous, S);
+ if (Previous.isAmbiguous() &&
+ (TUK == TUK_Definition || TUK == TUK_Declaration)) {
+ LookupResult::Filter F = Previous.makeFilter();
+ while (F.hasNext()) {
+ NamedDecl *ND = F.next();
+ if (ND->getDeclContext()->getRedeclContext() != SearchDC)
+ F.erase();
+ }
+ F.done();
+ }
+
// Note: there used to be some attempt at recovery here.
if (Previous.isAmbiguous())
return 0;
@@ -6846,7 +7013,9 @@ Decl *Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK,
isDeclInScope(PrevDecl, SearchDC, S, isExplicitSpecialization)) {
// Make sure that this wasn't declared as an enum and now used as a
// struct or something similar.
- if (!isAcceptableTagRedeclaration(PrevTagDecl, Kind, KWLoc, *Name)) {
+ if (!isAcceptableTagRedeclaration(PrevTagDecl, Kind,
+ TUK == TUK_Definition, KWLoc,
+ *Name)) {
bool SafeToContinue
= (PrevTagDecl->getTagKind() != TTK_Enum &&
Kind != TTK_Enum);
@@ -6911,8 +7080,8 @@ Decl *Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK,
// for the consumer of this Decl to know it doesn't own it.
// For our current ASTs this shouldn't be a problem, but will
// need to be changed with DeclGroups.
- if ((TUK == TUK_Reference && !PrevTagDecl->getFriendObjectKind()) ||
- TUK == TUK_Friend)
+ if ((TUK == TUK_Reference && (!PrevTagDecl->getFriendObjectKind() ||
+ getLangOptions().Microsoft)) || TUK == TUK_Friend)
return PrevTagDecl;
// Diagnose attempts to redefine a tag.
@@ -7154,8 +7323,12 @@ CreateNewDecl:
New->setLexicalDeclContext(CurContext);
// Mark this as a friend decl if applicable.
+ // In Microsoft mode, a friend declaration also acts as a forward
+ // declaration so we always pass true to setObjectOfFriendDecl to make
+ // the tag name visible.
if (TUK == TUK_Friend)
- New->setObjectOfFriendDecl(/* PreviouslyDeclared = */ !Previous.empty());
+ New->setObjectOfFriendDecl(/* PreviouslyDeclared = */ !Previous.empty() ||
+ getLangOptions().Microsoft);
// Set the access specifier.
if (!Invalid && SearchDC->isRecord())
@@ -7341,14 +7514,13 @@ bool Sema::VerifyBitField(SourceLocation FieldLoc, IdentifierInfo *FieldName,
return false;
}
-/// ActOnField - Each field of a struct/union/class is passed into this in order
+/// ActOnField - Each field of a C struct/union is passed into this in order
/// to create a FieldDecl object for it.
-Decl *Sema::ActOnField(Scope *S, Decl *TagD,
- SourceLocation DeclStart,
- Declarator &D, ExprTy *BitfieldWidth) {
+Decl *Sema::ActOnField(Scope *S, Decl *TagD, SourceLocation DeclStart,
+ Declarator &D, ExprTy *BitfieldWidth) {
FieldDecl *Res = HandleField(S, cast_or_null<RecordDecl>(TagD),
DeclStart, D, static_cast<Expr*>(BitfieldWidth),
- AS_public);
+ /*HasInit=*/false, AS_public);
return Res;
}
@@ -7356,7 +7528,7 @@ Decl *Sema::ActOnField(Scope *S, Decl *TagD,
///
FieldDecl *Sema::HandleField(Scope *S, RecordDecl *Record,
SourceLocation DeclStart,
- Declarator &D, Expr *BitWidth,
+ Declarator &D, Expr *BitWidth, bool HasInit,
AccessSpecifier AS) {
IdentifierInfo *II = D.getIdentifier();
SourceLocation Loc = DeclStart;
@@ -7405,8 +7577,8 @@ FieldDecl *Sema::HandleField(Scope *S, RecordDecl *Record,
= (D.getDeclSpec().getStorageClassSpec() == DeclSpec::SCS_mutable);
SourceLocation TSSL = D.getSourceRange().getBegin();
FieldDecl *NewFD
- = CheckFieldDecl(II, T, TInfo, Record, Loc, Mutable, BitWidth, TSSL,
- AS, PrevDecl, &D);
+ = CheckFieldDecl(II, T, TInfo, Record, Loc, Mutable, BitWidth, HasInit,
+ TSSL, AS, PrevDecl, &D);
if (NewFD->isInvalidDecl())
Record->setInvalidDecl();
@@ -7435,7 +7607,7 @@ FieldDecl *Sema::HandleField(Scope *S, RecordDecl *Record,
FieldDecl *Sema::CheckFieldDecl(DeclarationName Name, QualType T,
TypeSourceInfo *TInfo,
RecordDecl *Record, SourceLocation Loc,
- bool Mutable, Expr *BitWidth,
+ bool Mutable, Expr *BitWidth, bool HasInit,
SourceLocation TSSL,
AccessSpecifier AS, NamedDecl *PrevDecl,
Declarator *D) {
@@ -7515,7 +7687,7 @@ FieldDecl *Sema::CheckFieldDecl(DeclarationName Name, QualType T,
}
FieldDecl *NewFD = FieldDecl::Create(Context, Record, TSSL, Loc, II, T, TInfo,
- BitWidth, Mutable);
+ BitWidth, Mutable, HasInit);
if (InvalidDecl)
NewFD->setInvalidDecl();
@@ -7535,8 +7707,7 @@ FieldDecl *Sema::CheckFieldDecl(DeclarationName Name, QualType T,
// destructor, or a non-trivial copy assignment operator
// cannot be a member of a union, nor can an array of such
// objects.
- // TODO: C++0x alters this restriction significantly.
- if (CheckNontrivialField(NewFD))
+ if (!getLangOptions().CPlusPlus0x && CheckNontrivialField(NewFD))
NewFD->setInvalidDecl();
}
}
@@ -7582,8 +7753,8 @@ bool Sema::CheckNontrivialField(FieldDecl *FD) {
CXXSpecialMember member = CXXInvalid;
if (!RDecl->hasTrivialCopyConstructor())
member = CXXCopyConstructor;
- else if (!RDecl->hasTrivialConstructor())
- member = CXXConstructor;
+ else if (!RDecl->hasTrivialDefaultConstructor())
+ member = CXXDefaultConstructor;
else if (!RDecl->hasTrivialCopyAssignment())
member = CXXCopyAssignment;
else if (!RDecl->hasTrivialDestructor())
@@ -7612,7 +7783,7 @@ void Sema::DiagnoseNontrivial(const RecordType* T, CXXSpecialMember member) {
case CXXInvalid:
break;
- case CXXConstructor:
+ case CXXDefaultConstructor:
if (RD->hasUserDeclaredConstructor()) {
typedef CXXRecordDecl::ctor_iterator ctor_iter;
for (ctor_iter ci = RD->ctor_begin(), ce = RD->ctor_end(); ci != ce;++ci){
@@ -7633,7 +7804,15 @@ void Sema::DiagnoseNontrivial(const RecordType* T, CXXSpecialMember member) {
case CXXCopyConstructor:
if (RD->hasUserDeclaredCopyConstructor()) {
SourceLocation CtorLoc =
- RD->getCopyConstructor(Context, 0)->getLocation();
+ RD->getCopyConstructor(0)->getLocation();
+ Diag(CtorLoc, diag::note_nontrivial_user_defined) << QT << member;
+ return;
+ }
+ break;
+
+ case CXXMoveConstructor:
+ if (RD->hasUserDeclaredMoveConstructor()) {
+ SourceLocation CtorLoc = RD->getMoveConstructor()->getLocation();
Diag(CtorLoc, diag::note_nontrivial_user_defined) << QT << member;
return;
}
@@ -7649,6 +7828,14 @@ void Sema::DiagnoseNontrivial(const RecordType* T, CXXSpecialMember member) {
}
break;
+ case CXXMoveAssignment:
+ if (RD->hasUserDeclaredMoveAssignment()) {
+ SourceLocation AssignLoc = RD->getMoveAssignmentOperator()->getLocation();
+ Diag(AssignLoc, diag::note_nontrivial_user_defined) << QT << member;
+ return;
+ }
+ break;
+
case CXXDestructor:
if (RD->hasUserDeclaredDestructor()) {
SourceLocation DtorLoc = LookupDestructor(RD)->getLocation();
@@ -7686,8 +7873,8 @@ void Sema::DiagnoseNontrivial(const RecordType* T, CXXSpecialMember member) {
bool (CXXRecordDecl::*hasTrivial)() const;
switch (member) {
- case CXXConstructor:
- hasTrivial = &CXXRecordDecl::hasTrivialConstructor; break;
+ case CXXDefaultConstructor:
+ hasTrivial = &CXXRecordDecl::hasTrivialDefaultConstructor; break;
case CXXCopyConstructor:
hasTrivial = &CXXRecordDecl::hasTrivialCopyConstructor; break;
case CXXCopyAssignment:
@@ -8047,6 +8234,11 @@ void Sema::ActOnFields(Scope* S,
Convs->setAccess(I, (*I)->getAccess());
if (!CXXRecord->isDependentType()) {
+ // Adjust user-defined destructor exception spec.
+ if (getLangOptions().CPlusPlus0x &&
+ CXXRecord->hasUserDeclaredDestructor())
+ AdjustDestructorExceptionSpec(CXXRecord,CXXRecord->getDestructor());
+
// Add any implicitly-declared members to this class.
AddImplicitlyDeclaredMembersToClass(CXXRecord);
@@ -8095,6 +8287,22 @@ void Sema::ActOnFields(Scope* S,
if (!Completed)
Record->completeDefinition();
+
+ // Now that the record is complete, do any delayed exception spec checks
+ // we were missing.
+ while (!DelayedDestructorExceptionSpecChecks.empty()) {
+ const CXXDestructorDecl *Dtor =
+ DelayedDestructorExceptionSpecChecks.back().first;
+ if (Dtor->getParent() != Record)
+ break;
+
+ assert(!Dtor->getParent()->isDependentType() &&
+ "Should not ever add destructors of templates into the list.");
+ CheckOverridingFunctionExceptionSpec(Dtor,
+ DelayedDestructorExceptionSpecChecks.back().second);
+ DelayedDestructorExceptionSpecChecks.pop_back();
+ }
+
} else {
ObjCIvarDecl **ClsFields =
reinterpret_cast<ObjCIvarDecl**>(RecFields.data());
@@ -8149,7 +8357,7 @@ static bool isRepresentableIntegerValue(ASTContext &Context,
unsigned BitWidth = Context.getIntWidth(T);
if (Value.isUnsigned() || Value.isNonNegative()) {
- if (T->isSignedIntegerType())
+ if (T->isSignedIntegerOrEnumerationType())
--BitWidth;
return Value.getActiveBits() <= BitWidth;
}
@@ -8172,8 +8380,8 @@ static QualType getNextLargerIntegralType(ASTContext &Context, QualType T) {
};
unsigned BitWidth = Context.getTypeSize(T);
- QualType *Types = T->isSignedIntegerType()? SignedIntegralTypes
- : UnsignedIntegralTypes;
+ QualType *Types = T->isSignedIntegerOrEnumerationType()? SignedIntegralTypes
+ : UnsignedIntegralTypes;
for (unsigned I = 0; I != NumTypes; ++I)
if (Context.getTypeSize(Types[I]) > BitWidth)
return Types[I];
@@ -8307,7 +8515,7 @@ EnumConstantDecl *Sema::CheckEnumConstant(EnumDecl *Enum,
// type that is supposed to be large enough to represent the incremented
// value, then increment.
EnumVal = LastEnumConst->getInitVal();
- EnumVal.setIsSigned(EltTy->isSignedIntegerType());
+ EnumVal.setIsSigned(EltTy->isSignedIntegerOrEnumerationType());
EnumVal = EnumVal.zextOrTrunc(Context.getIntWidth(EltTy));
++EnumVal;
@@ -8331,7 +8539,7 @@ EnumConstantDecl *Sema::CheckEnumConstant(EnumDecl *Enum,
// Make the enumerator value match the signedness and size of the
// enumerator's type.
EnumVal = EnumVal.zextOrTrunc(Context.getIntWidth(EltTy));
- EnumVal.setIsSigned(EltTy->isSignedIntegerType());
+ EnumVal.setIsSigned(EltTy->isSignedIntegerOrEnumerationType());
}
return EnumConstantDecl::Create(Context, Enum, IdLoc, Id, EltTy,
@@ -8589,7 +8797,7 @@ void Sema::ActOnEnumBody(SourceLocation EnumLoc, SourceLocation LBraceLoc,
} else {
NewTy = BestType;
NewWidth = BestWidth;
- NewSign = BestType->isSignedIntegerType();
+ NewSign = BestType->isSignedIntegerOrEnumerationType();
}
// Adjust the APSInt value.
diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp
index 27632a1..ce99efb 100644
--- a/lib/Sema/SemaDeclCXX.cpp
+++ b/lib/Sema/SemaDeclCXX.cpp
@@ -111,6 +111,102 @@ namespace {
}
}
+void Sema::ImplicitExceptionSpecification::CalledDecl(CXXMethodDecl *Method) {
+ assert(Context && "ImplicitExceptionSpecification without an ASTContext");
+ // If we have an MSAny or unknown spec already, don't bother.
+ if (!Method || ComputedEST == EST_MSAny || ComputedEST == EST_Delayed)
+ return;
+
+ const FunctionProtoType *Proto
+ = Method->getType()->getAs<FunctionProtoType>();
+
+ ExceptionSpecificationType EST = Proto->getExceptionSpecType();
+
+ // If this function can throw any exceptions, make a note of that.
+ if (EST == EST_Delayed || EST == EST_MSAny || EST == EST_None) {
+ ClearExceptions();
+ ComputedEST = EST;
+ return;
+ }
+
+ // FIXME: If the call to this decl is using any of its default arguments, we
+ // need to search them for potentially-throwing calls.
+
+ // If this function has a basic noexcept, it doesn't affect the outcome.
+ if (EST == EST_BasicNoexcept)
+ return;
+
+ // If we have a throw-all spec at this point, ignore the function.
+ if (ComputedEST == EST_None)
+ return;
+
+ // If we're still at noexcept(true) and there's a nothrow() callee,
+ // change to that specification.
+ if (EST == EST_DynamicNone) {
+ if (ComputedEST == EST_BasicNoexcept)
+ ComputedEST = EST_DynamicNone;
+ return;
+ }
+
+ // Check out noexcept specs.
+ if (EST == EST_ComputedNoexcept) {
+ FunctionProtoType::NoexceptResult NR = Proto->getNoexceptSpec(*Context);
+ assert(NR != FunctionProtoType::NR_NoNoexcept &&
+ "Must have noexcept result for EST_ComputedNoexcept.");
+ assert(NR != FunctionProtoType::NR_Dependent &&
+ "Should not generate implicit declarations for dependent cases, "
+ "and don't know how to handle them anyway.");
+
+ // noexcept(false) -> no spec on the new function
+ if (NR == FunctionProtoType::NR_Throw) {
+ ClearExceptions();
+ ComputedEST = EST_None;
+ }
+ // noexcept(true) won't change anything either.
+ return;
+ }
+
+ assert(EST == EST_Dynamic && "EST case not considered earlier.");
+ assert(ComputedEST != EST_None &&
+ "Shouldn't collect exceptions when throw-all is guaranteed.");
+ ComputedEST = EST_Dynamic;
+ // Record the exceptions in this function's exception specification.
+ for (FunctionProtoType::exception_iterator E = Proto->exception_begin(),
+ EEnd = Proto->exception_end();
+ E != EEnd; ++E)
+ if (ExceptionsSeen.insert(Context->getCanonicalType(*E)))
+ Exceptions.push_back(*E);
+}
+
+void Sema::ImplicitExceptionSpecification::CalledExpr(Expr *E) {
+ if (!E || ComputedEST == EST_MSAny || ComputedEST == EST_Delayed)
+ return;
+
+ // FIXME:
+ //
+ // C++0x [except.spec]p14:
+ // [An] implicit exception-specification specifies the type-id T if and
+ // only if T is allowed by the exception-specification of a function directly
+ // invoked by f’s implicit definition; f shall allow all exceptions if any
+ // function it directly invokes allows all exceptions, and f shall allow no
+ // exceptions if every function it directly invokes allows no exceptions.
+ //
+ // Note in particular that if an implicit exception-specification is generated
+ // for a function containing a throw-expression, that specification can still
+ // be noexcept(true).
+ //
+ // Note also that 'directly invoked' is not defined in the standard, and there
+ // is no indication that we should only consider potentially-evaluated calls.
+ //
+ // Ultimately we should implement the intent of the standard: the exception
+ // specification should be the set of exceptions which can be thrown by the
+ // implicit definition. For now, we assume that any non-nothrow expression can
+ // throw any exception.
+
+ if (E->CanThrow(*Context))
+ ComputedEST = EST_None;
+}
+
bool
Sema::SetParamDefaultArgument(ParmVarDecl *Param, Expr *Arg,
SourceLocation EqualLoc) {
@@ -393,6 +489,15 @@ bool Sema::MergeCXXFunctionDecl(FunctionDecl *New, FunctionDecl *Old) {
diag::err_param_default_argument_member_template_redecl)
<< WhichKind
<< NewParam->getDefaultArgRange();
+ } else if (CXXConstructorDecl *Ctor = dyn_cast<CXXConstructorDecl>(New)) {
+ CXXSpecialMember NewSM = getSpecialMember(Ctor),
+ OldSM = getSpecialMember(cast<CXXConstructorDecl>(Old));
+ if (NewSM != OldSM) {
+ Diag(NewParam->getLocation(),diag::warn_default_arg_makes_ctor_special)
+ << NewParam->getDefaultArgRange() << NewSM;
+ Diag(Old->getLocation(), diag::note_previous_declaration_special)
+ << OldSM;
+ }
}
}
}
@@ -956,14 +1061,15 @@ bool Sema::CheckIfOverriddenFunctionIsMarkedFinal(const CXXMethodDecl *New,
/// ActOnCXXMemberDeclarator - This is invoked when a C++ class member
/// declarator is parsed. 'AS' is the access specifier, 'BW' specifies the
-/// bitfield width if there is one and 'InitExpr' specifies the initializer if
-/// any.
+/// bitfield width if there is one, 'InitExpr' specifies the initializer if
+/// one has been parsed, and 'HasDeferredInit' is true if an initializer is
+/// present but parsing it has been deferred.
Decl *
Sema::ActOnCXXMemberDeclarator(Scope *S, AccessSpecifier AS, Declarator &D,
MultiTemplateParamsArg TemplateParameterLists,
ExprTy *BW, const VirtSpecifiers &VS,
- ExprTy *InitExpr, bool IsDefinition,
- bool Deleted) {
+ ExprTy *InitExpr, bool HasDeferredInit,
+ bool IsDefinition) {
const DeclSpec &DS = D.getDeclSpec();
DeclarationNameInfo NameInfo = GetNameForDeclarator(D);
DeclarationName Name = NameInfo.getName();
@@ -978,6 +1084,7 @@ Sema::ActOnCXXMemberDeclarator(Scope *S, AccessSpecifier AS, Declarator &D,
assert(isa<CXXRecordDecl>(CurContext));
assert(!DS.isFriendSpecified());
+ assert(!Init || !HasDeferredInit);
bool isFunc = false;
if (D.isFunctionDeclarator())
@@ -1028,7 +1135,6 @@ Sema::ActOnCXXMemberDeclarator(Scope *S, AccessSpecifier AS, Declarator &D,
if (isInstField) {
CXXScopeSpec &SS = D.getCXXScopeSpec();
-
if (SS.isSet() && !SS.isInvalid()) {
// The user provided a superfluous scope specifier inside a class
// definition:
@@ -1050,9 +1156,11 @@ Sema::ActOnCXXMemberDeclarator(Scope *S, AccessSpecifier AS, Declarator &D,
// FIXME: Check for template parameters!
// FIXME: Check that the name is an identifier!
Member = HandleField(S, cast<CXXRecordDecl>(CurContext), Loc, D, BitWidth,
- AS);
+ HasDeferredInit, AS);
assert(Member && "HandleField never returns null");
} else {
+ assert(!HasDeferredInit);
+
Member = HandleDeclarator(S, D, move(TemplateParameterLists), IsDefinition);
if (!Member) {
return 0;
@@ -1123,8 +1231,14 @@ Sema::ActOnCXXMemberDeclarator(Scope *S, AccessSpecifier AS, Declarator &D,
if (Init)
AddInitializerToDecl(Member, Init, false,
DS.getTypeSpecType() == DeclSpec::TST_auto);
- if (Deleted) // FIXME: Source location is not very good.
- SetDeclDeleted(Member, D.getSourceRange().getBegin());
+ else if (DS.getTypeSpecType() == DeclSpec::TST_auto &&
+ DS.getStorageClassSpec() == DeclSpec::SCS_static) {
+ // C++0x [dcl.spec.auto]p4: 'auto' can only be used in the type of a static
+ // data member if a brace-or-equal-initializer is provided.
+ Diag(Loc, diag::err_auto_var_requires_init)
+ << Name << cast<ValueDecl>(Member)->getType();
+ Member->setInvalidDecl();
+ }
FinalizeDeclaration(Member);
@@ -1133,6 +1247,47 @@ Sema::ActOnCXXMemberDeclarator(Scope *S, AccessSpecifier AS, Declarator &D,
return Member;
}
+/// ActOnCXXInClassMemberInitializer - This is invoked after parsing an
+/// in-class initializer for a non-static C++ class member. Such parsing
+/// is deferred until the class is complete.
+void
+Sema::ActOnCXXInClassMemberInitializer(Decl *D, SourceLocation EqualLoc,
+ Expr *InitExpr) {
+ FieldDecl *FD = cast<FieldDecl>(D);
+
+ if (!InitExpr) {
+ FD->setInvalidDecl();
+ FD->removeInClassInitializer();
+ return;
+ }
+
+ ExprResult Init = InitExpr;
+ if (!FD->getType()->isDependentType() && !InitExpr->isTypeDependent()) {
+ // FIXME: if there is no EqualLoc, this is list-initialization.
+ Init = PerformCopyInitialization(
+ InitializedEntity::InitializeMember(FD), EqualLoc, InitExpr);
+ if (Init.isInvalid()) {
+ FD->setInvalidDecl();
+ return;
+ }
+
+ CheckImplicitConversions(Init.get(), EqualLoc);
+ }
+
+ // C++0x [class.base.init]p7:
+ // The initialization of each base and member constitutes a
+ // full-expression.
+ Init = MaybeCreateExprWithCleanups(Init);
+ if (Init.isInvalid()) {
+ FD->setInvalidDecl();
+ return;
+ }
+
+ InitExpr = Init.release();
+
+ FD->setInClassInitializer(InitExpr);
+}
+
/// \brief Find the direct and/or virtual base specifiers that
/// correspond to the given base type, for use in base initialization
/// within a constructor.
@@ -1547,7 +1702,8 @@ Sema::BuildDelegatingInitializer(TypeSourceInfo *TInfo,
return true;
CXXConstructExpr *ConExpr = cast<CXXConstructExpr>(DelegationInit.get());
- CXXConstructorDecl *Constructor = ConExpr->getConstructor();
+ CXXConstructorDecl *Constructor
+ = ConExpr->getConstructor();
assert(Constructor && "Delegating constructor with no target?");
CheckImplicitConversions(DelegationInit.get(), LParenLoc);
@@ -1956,24 +2112,26 @@ BuildImplicitMemberInitializer(Sema &SemaRef, CXXConstructorDecl *Constructor,
return false;
}
- if (FieldBaseElementType->isReferenceType()) {
- SemaRef.Diag(Constructor->getLocation(),
- diag::err_uninitialized_member_in_ctor)
- << (int)Constructor->isImplicit()
- << SemaRef.Context.getTagDeclType(Constructor->getParent())
- << 0 << Field->getDeclName();
- SemaRef.Diag(Field->getLocation(), diag::note_declared_at);
- return true;
- }
+ if (!Field->getParent()->isUnion()) {
+ if (FieldBaseElementType->isReferenceType()) {
+ SemaRef.Diag(Constructor->getLocation(),
+ diag::err_uninitialized_member_in_ctor)
+ << (int)Constructor->isImplicit()
+ << SemaRef.Context.getTagDeclType(Constructor->getParent())
+ << 0 << Field->getDeclName();
+ SemaRef.Diag(Field->getLocation(), diag::note_declared_at);
+ return true;
+ }
- if (FieldBaseElementType.isConstQualified()) {
- SemaRef.Diag(Constructor->getLocation(),
- diag::err_uninitialized_member_in_ctor)
- << (int)Constructor->isImplicit()
- << SemaRef.Context.getTagDeclType(Constructor->getParent())
- << 1 << Field->getDeclName();
- SemaRef.Diag(Field->getLocation(), diag::note_declared_at);
- return true;
+ if (FieldBaseElementType.isConstQualified()) {
+ SemaRef.Diag(Constructor->getLocation(),
+ diag::err_uninitialized_member_in_ctor)
+ << (int)Constructor->isImplicit()
+ << SemaRef.Context.getTagDeclType(Constructor->getParent())
+ << 1 << Field->getDeclName();
+ SemaRef.Diag(Field->getLocation(), diag::note_declared_at);
+ return true;
+ }
}
// Nothing to initialize.
@@ -2001,7 +2159,7 @@ struct BaseAndFieldInfo {
};
}
-static bool CollectFieldInitializer(BaseAndFieldInfo &Info,
+static bool CollectFieldInitializer(Sema &SemaRef, BaseAndFieldInfo &Info,
FieldDecl *Top, FieldDecl *Field) {
// Overwhelmingly common case: we have a direct initializer for this field.
@@ -2010,6 +2168,18 @@ static bool CollectFieldInitializer(BaseAndFieldInfo &Info,
return false;
}
+ // C++0x [class.base.init]p8: if the entity is a non-static data member that
+ // has a brace-or-equal-initializer, the entity is initialized as specified
+ // in [dcl.init].
+ if (Field->hasInClassInitializer()) {
+ Info.AllToInit.push_back(
+ new (SemaRef.Context) CXXCtorInitializer(SemaRef.Context, Field,
+ SourceLocation(),
+ SourceLocation(), 0,
+ SourceLocation()));
+ return false;
+ }
+
if (Info.IIK == IIK_Default && Field->isAnonymousStructOrUnion()) {
const RecordType *FieldClassType = Field->getType()->getAs<RecordType>();
assert(FieldClassType && "anonymous struct/union without record type");
@@ -2032,7 +2202,7 @@ static bool CollectFieldInitializer(BaseAndFieldInfo &Info,
// field in the class is also initialized, so exit immediately.
return false;
} else if ((*FA)->isAnonymousStructOrUnion()) {
- if (CollectFieldInitializer(Info, Top, *FA))
+ if (CollectFieldInitializer(SemaRef, Info, Top, *FA))
return true;
}
}
@@ -2047,7 +2217,7 @@ static bool CollectFieldInitializer(BaseAndFieldInfo &Info,
// necessary.
for (RecordDecl::field_iterator FA = FieldClassDecl->field_begin(),
EA = FieldClassDecl->field_end(); FA != EA; FA++) {
- if (CollectFieldInitializer(Info, Top, *FA))
+ if (CollectFieldInitializer(SemaRef, Info, Top, *FA))
return true;
}
}
@@ -2056,7 +2226,7 @@ static bool CollectFieldInitializer(BaseAndFieldInfo &Info,
// 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)
+ if (Info.AnyErrorsInInits || Field->isInvalidDecl())
return false;
CXXCtorInitializer *Init = 0;
@@ -2072,26 +2242,22 @@ static bool CollectFieldInitializer(BaseAndFieldInfo &Info,
bool
Sema::SetDelegatingInitializer(CXXConstructorDecl *Constructor,
CXXCtorInitializer *Initializer) {
+ assert(Initializer->isDelegatingInitializer());
Constructor->setNumCtorInitializers(1);
CXXCtorInitializer **initializer =
new (Context) CXXCtorInitializer*[1];
memcpy(initializer, &Initializer, sizeof (CXXCtorInitializer*));
Constructor->setCtorInitializers(initializer);
- // FIXME: This doesn't catch indirect loops yet
- CXXConstructorDecl *Target = Initializer->getTargetConstructor();
- while (Target) {
- if (Target == Constructor) {
- Diag(Initializer->getSourceLocation(), diag::err_delegating_ctor_loop)
- << Constructor;
- return true;
- }
- Target = Target->getTargetConstructor();
+ if (CXXDestructorDecl *Dtor = LookupDestructor(Constructor->getParent())) {
+ MarkDeclarationReferenced(Initializer->getSourceLocation(), Dtor);
+ DiagnoseUseOfDecl(Dtor, Initializer->getSourceLocation());
}
+ DelegatingCtorDecls.push_back(Constructor);
+
return false;
}
-
bool
Sema::SetCtorInitializers(CXXConstructorDecl *Constructor,
@@ -2192,7 +2358,7 @@ Sema::SetCtorInitializers(CXXConstructorDecl *Constructor,
"Incomplete array type is not valid");
continue;
}
- if (CollectFieldInitializer(Info, *Field, *Field))
+ if (CollectFieldInitializer(*this, Info, *Field, *Field))
HadError = true;
}
@@ -2468,7 +2634,7 @@ void Sema::ActOnMemInitializers(Decl *ConstructorDecl,
HadError = true;
// We will treat this as being the only initializer.
}
- SetDelegatingInitializer(Constructor, *MemInits);
+ SetDelegatingInitializer(Constructor, MemInits[i]);
// Return immediately as the initializer is set.
return;
}
@@ -2805,7 +2971,7 @@ static void CheckAbstractClassUsage(AbstractUsageInfo &Info,
CXXMethodDecl *MD) {
// No need to do the check on definitions, which require that
// the return/param types be complete.
- if (MD->isThisDeclarationADefinition())
+ if (MD->doesThisDeclarationHaveABody())
return;
// For safety's sake, just ignore it if we don't have type source
@@ -2871,6 +3037,9 @@ void Sema::CheckCompletedCXXClass(CXXRecordDecl *Record) {
for (RecordDecl::field_iterator F = Record->field_begin(),
FEnd = Record->field_end();
F != FEnd; ++F) {
+ if (F->hasInClassInitializer())
+ continue;
+
if (F->getType()->isReferenceType() ||
(F->getType().isConstQualified() && F->getType()->isScalarType())) {
if (!Complained) {
@@ -2937,6 +3106,953 @@ void Sema::CheckCompletedCXXClass(CXXRecordDecl *Record) {
// instantiated (e.g. meta-functions). This doesn't apply to classes that
// have inherited constructors.
DeclareInheritedConstructors(Record);
+
+ if (!Record->isDependentType())
+ CheckExplicitlyDefaultedMethods(Record);
+}
+
+void Sema::CheckExplicitlyDefaultedMethods(CXXRecordDecl *Record) {
+ for (CXXRecordDecl::method_iterator MI = Record->method_begin(),
+ ME = Record->method_end();
+ MI != ME; ++MI) {
+ if (!MI->isInvalidDecl() && MI->isExplicitlyDefaulted()) {
+ switch (getSpecialMember(*MI)) {
+ case CXXDefaultConstructor:
+ CheckExplicitlyDefaultedDefaultConstructor(
+ cast<CXXConstructorDecl>(*MI));
+ break;
+
+ case CXXDestructor:
+ CheckExplicitlyDefaultedDestructor(cast<CXXDestructorDecl>(*MI));
+ break;
+
+ case CXXCopyConstructor:
+ CheckExplicitlyDefaultedCopyConstructor(cast<CXXConstructorDecl>(*MI));
+ break;
+
+ case CXXCopyAssignment:
+ CheckExplicitlyDefaultedCopyAssignment(*MI);
+ break;
+
+ case CXXMoveConstructor:
+ case CXXMoveAssignment:
+ Diag(MI->getLocation(), diag::err_defaulted_move_unsupported);
+ break;
+
+ default:
+ // FIXME: Do moves once they exist
+ llvm_unreachable("non-special member explicitly defaulted!");
+ }
+ }
+ }
+
+}
+
+void Sema::CheckExplicitlyDefaultedDefaultConstructor(CXXConstructorDecl *CD) {
+ assert(CD->isExplicitlyDefaulted() && CD->isDefaultConstructor());
+
+ // Whether this was the first-declared instance of the constructor.
+ // This affects whether we implicitly add an exception spec (and, eventually,
+ // constexpr). It is also ill-formed to explicitly default a constructor such
+ // that it would be deleted. (C++0x [decl.fct.def.default])
+ bool First = CD == CD->getCanonicalDecl();
+
+ bool HadError = false;
+ if (CD->getNumParams() != 0) {
+ Diag(CD->getLocation(), diag::err_defaulted_default_ctor_params)
+ << CD->getSourceRange();
+ HadError = true;
+ }
+
+ ImplicitExceptionSpecification Spec
+ = ComputeDefaultedDefaultCtorExceptionSpec(CD->getParent());
+ FunctionProtoType::ExtProtoInfo EPI = Spec.getEPI();
+ if (EPI.ExceptionSpecType == EST_Delayed) {
+ // Exception specification depends on some deferred part of the class. We'll
+ // try again when the class's definition has been fully processed.
+ return;
+ }
+ const FunctionProtoType *CtorType = CD->getType()->getAs<FunctionProtoType>(),
+ *ExceptionType = Context.getFunctionType(
+ Context.VoidTy, 0, 0, EPI)->getAs<FunctionProtoType>();
+
+ if (CtorType->hasExceptionSpec()) {
+ if (CheckEquivalentExceptionSpec(
+ PDiag(diag::err_incorrect_defaulted_exception_spec)
+ << CXXDefaultConstructor,
+ PDiag(),
+ ExceptionType, SourceLocation(),
+ CtorType, CD->getLocation())) {
+ HadError = true;
+ }
+ } else if (First) {
+ // We set the declaration to have the computed exception spec here.
+ // We know there are no parameters.
+ EPI.ExtInfo = CtorType->getExtInfo();
+ CD->setType(Context.getFunctionType(Context.VoidTy, 0, 0, EPI));
+ }
+
+ if (HadError) {
+ CD->setInvalidDecl();
+ return;
+ }
+
+ if (ShouldDeleteDefaultConstructor(CD)) {
+ if (First) {
+ CD->setDeletedAsWritten();
+ } else {
+ Diag(CD->getLocation(), diag::err_out_of_line_default_deletes)
+ << CXXDefaultConstructor;
+ CD->setInvalidDecl();
+ }
+ }
+}
+
+void Sema::CheckExplicitlyDefaultedCopyConstructor(CXXConstructorDecl *CD) {
+ assert(CD->isExplicitlyDefaulted() && CD->isCopyConstructor());
+
+ // Whether this was the first-declared instance of the constructor.
+ bool First = CD == CD->getCanonicalDecl();
+
+ bool HadError = false;
+ if (CD->getNumParams() != 1) {
+ Diag(CD->getLocation(), diag::err_defaulted_copy_ctor_params)
+ << CD->getSourceRange();
+ HadError = true;
+ }
+
+ ImplicitExceptionSpecification Spec(Context);
+ bool Const;
+ llvm::tie(Spec, Const) =
+ ComputeDefaultedCopyCtorExceptionSpecAndConst(CD->getParent());
+
+ FunctionProtoType::ExtProtoInfo EPI = Spec.getEPI();
+ const FunctionProtoType *CtorType = CD->getType()->getAs<FunctionProtoType>(),
+ *ExceptionType = Context.getFunctionType(
+ Context.VoidTy, 0, 0, EPI)->getAs<FunctionProtoType>();
+
+ // Check for parameter type matching.
+ // This is a copy ctor so we know it's a cv-qualified reference to T.
+ QualType ArgType = CtorType->getArgType(0);
+ if (ArgType->getPointeeType().isVolatileQualified()) {
+ Diag(CD->getLocation(), diag::err_defaulted_copy_ctor_volatile_param);
+ HadError = true;
+ }
+ if (ArgType->getPointeeType().isConstQualified() && !Const) {
+ Diag(CD->getLocation(), diag::err_defaulted_copy_ctor_const_param);
+ HadError = true;
+ }
+
+ if (CtorType->hasExceptionSpec()) {
+ if (CheckEquivalentExceptionSpec(
+ PDiag(diag::err_incorrect_defaulted_exception_spec)
+ << CXXCopyConstructor,
+ PDiag(),
+ ExceptionType, SourceLocation(),
+ CtorType, CD->getLocation())) {
+ HadError = true;
+ }
+ } else if (First) {
+ // We set the declaration to have the computed exception spec here.
+ // We duplicate the one parameter type.
+ EPI.ExtInfo = CtorType->getExtInfo();
+ CD->setType(Context.getFunctionType(Context.VoidTy, &ArgType, 1, EPI));
+ }
+
+ if (HadError) {
+ CD->setInvalidDecl();
+ return;
+ }
+
+ if (ShouldDeleteCopyConstructor(CD)) {
+ if (First) {
+ CD->setDeletedAsWritten();
+ } else {
+ Diag(CD->getLocation(), diag::err_out_of_line_default_deletes)
+ << CXXCopyConstructor;
+ CD->setInvalidDecl();
+ }
+ }
+}
+
+void Sema::CheckExplicitlyDefaultedCopyAssignment(CXXMethodDecl *MD) {
+ assert(MD->isExplicitlyDefaulted());
+
+ // Whether this was the first-declared instance of the operator
+ bool First = MD == MD->getCanonicalDecl();
+
+ bool HadError = false;
+ if (MD->getNumParams() != 1) {
+ Diag(MD->getLocation(), diag::err_defaulted_copy_assign_params)
+ << MD->getSourceRange();
+ HadError = true;
+ }
+
+ QualType ReturnType =
+ MD->getType()->getAs<FunctionType>()->getResultType();
+ if (!ReturnType->isLValueReferenceType() ||
+ !Context.hasSameType(
+ Context.getCanonicalType(ReturnType->getPointeeType()),
+ Context.getCanonicalType(Context.getTypeDeclType(MD->getParent())))) {
+ Diag(MD->getLocation(), diag::err_defaulted_copy_assign_return_type);
+ HadError = true;
+ }
+
+ ImplicitExceptionSpecification Spec(Context);
+ bool Const;
+ llvm::tie(Spec, Const) =
+ ComputeDefaultedCopyCtorExceptionSpecAndConst(MD->getParent());
+
+ FunctionProtoType::ExtProtoInfo EPI = Spec.getEPI();
+ const FunctionProtoType *OperType = MD->getType()->getAs<FunctionProtoType>(),
+ *ExceptionType = Context.getFunctionType(
+ Context.VoidTy, 0, 0, EPI)->getAs<FunctionProtoType>();
+
+ QualType ArgType = OperType->getArgType(0);
+ if (!ArgType->isReferenceType()) {
+ Diag(MD->getLocation(), diag::err_defaulted_copy_assign_not_ref);
+ HadError = true;
+ } else {
+ if (ArgType->getPointeeType().isVolatileQualified()) {
+ Diag(MD->getLocation(), diag::err_defaulted_copy_assign_volatile_param);
+ HadError = true;
+ }
+ if (ArgType->getPointeeType().isConstQualified() && !Const) {
+ Diag(MD->getLocation(), diag::err_defaulted_copy_assign_const_param);
+ HadError = true;
+ }
+ }
+
+ if (OperType->getTypeQuals()) {
+ Diag(MD->getLocation(), diag::err_defaulted_copy_assign_quals);
+ HadError = true;
+ }
+
+ if (OperType->hasExceptionSpec()) {
+ if (CheckEquivalentExceptionSpec(
+ PDiag(diag::err_incorrect_defaulted_exception_spec)
+ << CXXCopyAssignment,
+ PDiag(),
+ ExceptionType, SourceLocation(),
+ OperType, MD->getLocation())) {
+ HadError = true;
+ }
+ } else if (First) {
+ // We set the declaration to have the computed exception spec here.
+ // We duplicate the one parameter type.
+ EPI.RefQualifier = OperType->getRefQualifier();
+ EPI.ExtInfo = OperType->getExtInfo();
+ MD->setType(Context.getFunctionType(ReturnType, &ArgType, 1, EPI));
+ }
+
+ if (HadError) {
+ MD->setInvalidDecl();
+ return;
+ }
+
+ if (ShouldDeleteCopyAssignmentOperator(MD)) {
+ if (First) {
+ MD->setDeletedAsWritten();
+ } else {
+ Diag(MD->getLocation(), diag::err_out_of_line_default_deletes)
+ << CXXCopyAssignment;
+ MD->setInvalidDecl();
+ }
+ }
+}
+
+void Sema::CheckExplicitlyDefaultedDestructor(CXXDestructorDecl *DD) {
+ assert(DD->isExplicitlyDefaulted());
+
+ // Whether this was the first-declared instance of the destructor.
+ bool First = DD == DD->getCanonicalDecl();
+
+ ImplicitExceptionSpecification Spec
+ = ComputeDefaultedDtorExceptionSpec(DD->getParent());
+ FunctionProtoType::ExtProtoInfo EPI = Spec.getEPI();
+ const FunctionProtoType *DtorType = DD->getType()->getAs<FunctionProtoType>(),
+ *ExceptionType = Context.getFunctionType(
+ Context.VoidTy, 0, 0, EPI)->getAs<FunctionProtoType>();
+
+ if (DtorType->hasExceptionSpec()) {
+ if (CheckEquivalentExceptionSpec(
+ PDiag(diag::err_incorrect_defaulted_exception_spec)
+ << CXXDestructor,
+ PDiag(),
+ ExceptionType, SourceLocation(),
+ DtorType, DD->getLocation())) {
+ DD->setInvalidDecl();
+ return;
+ }
+ } else if (First) {
+ // We set the declaration to have the computed exception spec here.
+ // There are no parameters.
+ EPI.ExtInfo = DtorType->getExtInfo();
+ DD->setType(Context.getFunctionType(Context.VoidTy, 0, 0, EPI));
+ }
+
+ if (ShouldDeleteDestructor(DD)) {
+ if (First) {
+ DD->setDeletedAsWritten();
+ } else {
+ Diag(DD->getLocation(), diag::err_out_of_line_default_deletes)
+ << CXXDestructor;
+ DD->setInvalidDecl();
+ }
+ }
+}
+
+bool Sema::ShouldDeleteDefaultConstructor(CXXConstructorDecl *CD) {
+ CXXRecordDecl *RD = CD->getParent();
+ assert(!RD->isDependentType() && "do deletion after instantiation");
+ if (!LangOpts.CPlusPlus0x)
+ return false;
+
+ SourceLocation Loc = CD->getLocation();
+
+ // Do access control from the constructor
+ ContextRAII CtorContext(*this, CD);
+
+ bool Union = RD->isUnion();
+ bool AllConst = true;
+
+ // We do this because we should never actually use an anonymous
+ // union's constructor.
+ if (Union && RD->isAnonymousStructOrUnion())
+ return false;
+
+ // FIXME: We should put some diagnostic logic right into this function.
+
+ // C++0x [class.ctor]/5
+ // A defaulted default constructor for class X is defined as deleted if:
+
+ for (CXXRecordDecl::base_class_iterator BI = RD->bases_begin(),
+ BE = RD->bases_end();
+ BI != BE; ++BI) {
+ // We'll handle this one later
+ if (BI->isVirtual())
+ continue;
+
+ CXXRecordDecl *BaseDecl = BI->getType()->getAsCXXRecordDecl();
+ assert(BaseDecl && "base isn't a CXXRecordDecl");
+
+ // -- any [direct base class] has a type with a destructor that is
+ // deleted or inaccessible from the defaulted default constructor
+ CXXDestructorDecl *BaseDtor = LookupDestructor(BaseDecl);
+ if (BaseDtor->isDeleted())
+ return true;
+ if (CheckDestructorAccess(Loc, BaseDtor, PDiag()) !=
+ AR_accessible)
+ return true;
+
+ // -- any [direct base class either] has no default constructor or
+ // overload resolution as applied to [its] default constructor
+ // results in an ambiguity or in a function that is deleted or
+ // inaccessible from the defaulted default constructor
+ CXXConstructorDecl *BaseDefault = LookupDefaultConstructor(BaseDecl);
+ if (!BaseDefault || BaseDefault->isDeleted())
+ return true;
+
+ if (CheckConstructorAccess(Loc, BaseDefault, BaseDefault->getAccess(),
+ PDiag()) != AR_accessible)
+ return true;
+ }
+
+ for (CXXRecordDecl::base_class_iterator BI = RD->vbases_begin(),
+ BE = RD->vbases_end();
+ BI != BE; ++BI) {
+ CXXRecordDecl *BaseDecl = BI->getType()->getAsCXXRecordDecl();
+ assert(BaseDecl && "base isn't a CXXRecordDecl");
+
+ // -- any [virtual base class] has a type with a destructor that is
+ // delete or inaccessible from the defaulted default constructor
+ CXXDestructorDecl *BaseDtor = LookupDestructor(BaseDecl);
+ if (BaseDtor->isDeleted())
+ return true;
+ if (CheckDestructorAccess(Loc, BaseDtor, PDiag()) !=
+ AR_accessible)
+ return true;
+
+ // -- any [virtual base class either] has no default constructor or
+ // overload resolution as applied to [its] default constructor
+ // results in an ambiguity or in a function that is deleted or
+ // inaccessible from the defaulted default constructor
+ CXXConstructorDecl *BaseDefault = LookupDefaultConstructor(BaseDecl);
+ if (!BaseDefault || BaseDefault->isDeleted())
+ return true;
+
+ if (CheckConstructorAccess(Loc, BaseDefault, BaseDefault->getAccess(),
+ PDiag()) != AR_accessible)
+ return true;
+ }
+
+ for (CXXRecordDecl::field_iterator FI = RD->field_begin(),
+ FE = RD->field_end();
+ FI != FE; ++FI) {
+ if (FI->isInvalidDecl())
+ continue;
+
+ QualType FieldType = Context.getBaseElementType(FI->getType());
+ CXXRecordDecl *FieldRecord = FieldType->getAsCXXRecordDecl();
+
+ // -- any non-static data member with no brace-or-equal-initializer is of
+ // reference type
+ if (FieldType->isReferenceType() && !FI->hasInClassInitializer())
+ return true;
+
+ // -- X is a union and all its variant members are of const-qualified type
+ // (or array thereof)
+ if (Union && !FieldType.isConstQualified())
+ AllConst = false;
+
+ if (FieldRecord) {
+ // -- X is a union-like class that has a variant member with a non-trivial
+ // default constructor
+ if (Union && !FieldRecord->hasTrivialDefaultConstructor())
+ return true;
+
+ CXXDestructorDecl *FieldDtor = LookupDestructor(FieldRecord);
+ if (FieldDtor->isDeleted())
+ return true;
+ if (CheckDestructorAccess(Loc, FieldDtor, PDiag()) !=
+ AR_accessible)
+ return true;
+
+ // -- any non-variant non-static data member of const-qualified type (or
+ // array thereof) with no brace-or-equal-initializer does not have a
+ // user-provided default constructor
+ if (FieldType.isConstQualified() &&
+ !FI->hasInClassInitializer() &&
+ !FieldRecord->hasUserProvidedDefaultConstructor())
+ return true;
+
+ if (!Union && FieldRecord->isUnion() &&
+ FieldRecord->isAnonymousStructOrUnion()) {
+ // We're okay to reuse AllConst here since we only care about the
+ // value otherwise if we're in a union.
+ AllConst = true;
+
+ for (CXXRecordDecl::field_iterator UI = FieldRecord->field_begin(),
+ UE = FieldRecord->field_end();
+ UI != UE; ++UI) {
+ QualType UnionFieldType = Context.getBaseElementType(UI->getType());
+ CXXRecordDecl *UnionFieldRecord =
+ UnionFieldType->getAsCXXRecordDecl();
+
+ if (!UnionFieldType.isConstQualified())
+ AllConst = false;
+
+ if (UnionFieldRecord &&
+ !UnionFieldRecord->hasTrivialDefaultConstructor())
+ return true;
+ }
+
+ if (AllConst)
+ return true;
+
+ // Don't try to initialize the anonymous union
+ // This is technically non-conformant, but sanity demands it.
+ continue;
+ }
+
+ // -- any non-static data member with no brace-or-equal-initializer has
+ // class type M (or array thereof) and either M has no default
+ // constructor or overload resolution as applied to M's default
+ // constructor results in an ambiguity or in a function that is deleted
+ // or inaccessible from the defaulted default constructor.
+ if (!FI->hasInClassInitializer()) {
+ CXXConstructorDecl *FieldDefault = LookupDefaultConstructor(FieldRecord);
+ if (!FieldDefault || FieldDefault->isDeleted())
+ return true;
+ if (CheckConstructorAccess(Loc, FieldDefault, FieldDefault->getAccess(),
+ PDiag()) != AR_accessible)
+ return true;
+ }
+ } else if (!Union && FieldType.isConstQualified() &&
+ !FI->hasInClassInitializer()) {
+ // -- any non-variant non-static data member of const-qualified type (or
+ // array thereof) with no brace-or-equal-initializer does not have a
+ // user-provided default constructor
+ return true;
+ }
+ }
+
+ if (Union && AllConst)
+ return true;
+
+ return false;
+}
+
+bool Sema::ShouldDeleteCopyConstructor(CXXConstructorDecl *CD) {
+ CXXRecordDecl *RD = CD->getParent();
+ assert(!RD->isDependentType() && "do deletion after instantiation");
+ if (!LangOpts.CPlusPlus0x)
+ return false;
+
+ SourceLocation Loc = CD->getLocation();
+
+ // Do access control from the constructor
+ ContextRAII CtorContext(*this, CD);
+
+ bool Union = RD->isUnion();
+
+ assert(!CD->getParamDecl(0)->getType()->getPointeeType().isNull() &&
+ "copy assignment arg has no pointee type");
+ unsigned ArgQuals =
+ CD->getParamDecl(0)->getType()->getPointeeType().isConstQualified() ?
+ Qualifiers::Const : 0;
+
+ // We do this because we should never actually use an anonymous
+ // union's constructor.
+ if (Union && RD->isAnonymousStructOrUnion())
+ return false;
+
+ // FIXME: We should put some diagnostic logic right into this function.
+
+ // C++0x [class.copy]/11
+ // A defaulted [copy] constructor for class X is defined as delete if X has:
+
+ for (CXXRecordDecl::base_class_iterator BI = RD->bases_begin(),
+ BE = RD->bases_end();
+ BI != BE; ++BI) {
+ // We'll handle this one later
+ if (BI->isVirtual())
+ continue;
+
+ QualType BaseType = BI->getType();
+ CXXRecordDecl *BaseDecl = BaseType->getAsCXXRecordDecl();
+ assert(BaseDecl && "base isn't a CXXRecordDecl");
+
+ // -- any [direct base class] of a type with a destructor that is deleted or
+ // inaccessible from the defaulted constructor
+ CXXDestructorDecl *BaseDtor = LookupDestructor(BaseDecl);
+ if (BaseDtor->isDeleted())
+ return true;
+ if (CheckDestructorAccess(Loc, BaseDtor, PDiag()) !=
+ AR_accessible)
+ return true;
+
+ // -- a [direct base class] B that cannot be [copied] because overload
+ // resolution, as applied to B's [copy] constructor, results in an
+ // ambiguity or a function that is deleted or inaccessible from the
+ // defaulted constructor
+ CXXConstructorDecl *BaseCtor = LookupCopyConstructor(BaseDecl, ArgQuals);
+ if (!BaseCtor || BaseCtor->isDeleted())
+ return true;
+ if (CheckConstructorAccess(Loc, BaseCtor, BaseCtor->getAccess(), PDiag()) !=
+ AR_accessible)
+ return true;
+ }
+
+ for (CXXRecordDecl::base_class_iterator BI = RD->vbases_begin(),
+ BE = RD->vbases_end();
+ BI != BE; ++BI) {
+ QualType BaseType = BI->getType();
+ CXXRecordDecl *BaseDecl = BaseType->getAsCXXRecordDecl();
+ assert(BaseDecl && "base isn't a CXXRecordDecl");
+
+ // -- any [virtual base class] of a type with a destructor that is deleted or
+ // inaccessible from the defaulted constructor
+ CXXDestructorDecl *BaseDtor = LookupDestructor(BaseDecl);
+ if (BaseDtor->isDeleted())
+ return true;
+ if (CheckDestructorAccess(Loc, BaseDtor, PDiag()) !=
+ AR_accessible)
+ return true;
+
+ // -- a [virtual base class] B that cannot be [copied] because overload
+ // resolution, as applied to B's [copy] constructor, results in an
+ // ambiguity or a function that is deleted or inaccessible from the
+ // defaulted constructor
+ CXXConstructorDecl *BaseCtor = LookupCopyConstructor(BaseDecl, ArgQuals);
+ if (!BaseCtor || BaseCtor->isDeleted())
+ return true;
+ if (CheckConstructorAccess(Loc, BaseCtor, BaseCtor->getAccess(), PDiag()) !=
+ AR_accessible)
+ return true;
+ }
+
+ for (CXXRecordDecl::field_iterator FI = RD->field_begin(),
+ FE = RD->field_end();
+ FI != FE; ++FI) {
+ QualType FieldType = Context.getBaseElementType(FI->getType());
+
+ // -- for a copy constructor, a non-static data member of rvalue reference
+ // type
+ if (FieldType->isRValueReferenceType())
+ return true;
+
+ CXXRecordDecl *FieldRecord = FieldType->getAsCXXRecordDecl();
+
+ if (FieldRecord) {
+ // This is an anonymous union
+ if (FieldRecord->isUnion() && FieldRecord->isAnonymousStructOrUnion()) {
+ // Anonymous unions inside unions do not variant members create
+ if (!Union) {
+ for (CXXRecordDecl::field_iterator UI = FieldRecord->field_begin(),
+ UE = FieldRecord->field_end();
+ UI != UE; ++UI) {
+ QualType UnionFieldType = Context.getBaseElementType(UI->getType());
+ CXXRecordDecl *UnionFieldRecord =
+ UnionFieldType->getAsCXXRecordDecl();
+
+ // -- a variant member with a non-trivial [copy] constructor and X
+ // is a union-like class
+ if (UnionFieldRecord &&
+ !UnionFieldRecord->hasTrivialCopyConstructor())
+ return true;
+ }
+ }
+
+ // Don't try to initalize an anonymous union
+ continue;
+ } else {
+ // -- a variant member with a non-trivial [copy] constructor and X is a
+ // union-like class
+ if (Union && !FieldRecord->hasTrivialCopyConstructor())
+ return true;
+
+ // -- any [non-static data member] of a type with a destructor that is
+ // deleted or inaccessible from the defaulted constructor
+ CXXDestructorDecl *FieldDtor = LookupDestructor(FieldRecord);
+ if (FieldDtor->isDeleted())
+ return true;
+ if (CheckDestructorAccess(Loc, FieldDtor, PDiag()) !=
+ AR_accessible)
+ return true;
+ }
+
+ // -- a [non-static data member of class type (or array thereof)] B that
+ // cannot be [copied] because overload resolution, as applied to B's
+ // [copy] constructor, results in an ambiguity or a function that is
+ // deleted or inaccessible from the defaulted constructor
+ CXXConstructorDecl *FieldCtor = LookupCopyConstructor(FieldRecord,
+ ArgQuals);
+ if (!FieldCtor || FieldCtor->isDeleted())
+ return true;
+ if (CheckConstructorAccess(Loc, FieldCtor, FieldCtor->getAccess(),
+ PDiag()) != AR_accessible)
+ return true;
+ }
+ }
+
+ return false;
+}
+
+bool Sema::ShouldDeleteCopyAssignmentOperator(CXXMethodDecl *MD) {
+ CXXRecordDecl *RD = MD->getParent();
+ assert(!RD->isDependentType() && "do deletion after instantiation");
+ if (!LangOpts.CPlusPlus0x)
+ return false;
+
+ SourceLocation Loc = MD->getLocation();
+
+ // Do access control from the constructor
+ ContextRAII MethodContext(*this, MD);
+
+ bool Union = RD->isUnion();
+
+ bool ConstArg =
+ MD->getParamDecl(0)->getType()->getPointeeType().isConstQualified();
+
+ // We do this because we should never actually use an anonymous
+ // union's constructor.
+ if (Union && RD->isAnonymousStructOrUnion())
+ return false;
+
+ DeclarationName OperatorName =
+ Context.DeclarationNames.getCXXOperatorName(OO_Equal);
+ LookupResult R(*this, OperatorName, Loc, LookupOrdinaryName);
+ R.suppressDiagnostics();
+
+ // FIXME: We should put some diagnostic logic right into this function.
+
+ // C++0x [class.copy]/11
+ // A defaulted [copy] assignment operator for class X is defined as deleted
+ // if X has:
+
+ for (CXXRecordDecl::base_class_iterator BI = RD->bases_begin(),
+ BE = RD->bases_end();
+ BI != BE; ++BI) {
+ // We'll handle this one later
+ if (BI->isVirtual())
+ continue;
+
+ QualType BaseType = BI->getType();
+ CXXRecordDecl *BaseDecl = BaseType->getAsCXXRecordDecl();
+ assert(BaseDecl && "base isn't a CXXRecordDecl");
+
+ // -- a [direct base class] B that cannot be [copied] because overload
+ // resolution, as applied to B's [copy] assignment operator, results in
+ // an ambiguity or a function that is deleted or inaccessible from the
+ // assignment operator
+
+ LookupQualifiedName(R, BaseDecl, false);
+
+ // Filter out any result that isn't a copy-assignment operator.
+ LookupResult::Filter F = R.makeFilter();
+ while (F.hasNext()) {
+ NamedDecl *D = F.next();
+ if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(D))
+ if (Method->isCopyAssignmentOperator())
+ continue;
+
+ F.erase();
+ }
+ F.done();
+
+ // Build a fake argument expression
+ QualType ArgType = BaseType;
+ QualType ThisType = BaseType;
+ if (ConstArg)
+ ArgType.addConst();
+ Expr *Args[] = { new (Context) OpaqueValueExpr(Loc, ThisType, VK_LValue)
+ , new (Context) OpaqueValueExpr(Loc, ArgType, VK_LValue)
+ };
+
+ OverloadCandidateSet OCS((Loc));
+ OverloadCandidateSet::iterator Best;
+
+ AddFunctionCandidates(R.asUnresolvedSet(), Args, 2, OCS);
+
+ if (OCS.BestViableFunction(*this, Loc, Best, false) !=
+ OR_Success)
+ return true;
+ }
+
+ for (CXXRecordDecl::base_class_iterator BI = RD->vbases_begin(),
+ BE = RD->vbases_end();
+ BI != BE; ++BI) {
+ QualType BaseType = BI->getType();
+ CXXRecordDecl *BaseDecl = BaseType->getAsCXXRecordDecl();
+ assert(BaseDecl && "base isn't a CXXRecordDecl");
+
+ // -- a [virtual base class] B that cannot be [copied] because overload
+ // resolution, as applied to B's [copy] assignment operator, results in
+ // an ambiguity or a function that is deleted or inaccessible from the
+ // assignment operator
+
+ LookupQualifiedName(R, BaseDecl, false);
+
+ // Filter out any result that isn't a copy-assignment operator.
+ LookupResult::Filter F = R.makeFilter();
+ while (F.hasNext()) {
+ NamedDecl *D = F.next();
+ if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(D))
+ if (Method->isCopyAssignmentOperator())
+ continue;
+
+ F.erase();
+ }
+ F.done();
+
+ // Build a fake argument expression
+ QualType ArgType = BaseType;
+ QualType ThisType = BaseType;
+ if (ConstArg)
+ ArgType.addConst();
+ Expr *Args[] = { new (Context) OpaqueValueExpr(Loc, ThisType, VK_LValue)
+ , new (Context) OpaqueValueExpr(Loc, ArgType, VK_LValue)
+ };
+
+ OverloadCandidateSet OCS((Loc));
+ OverloadCandidateSet::iterator Best;
+
+ AddFunctionCandidates(R.asUnresolvedSet(), Args, 2, OCS);
+
+ if (OCS.BestViableFunction(*this, Loc, Best, false) !=
+ OR_Success)
+ return true;
+ }
+
+ for (CXXRecordDecl::field_iterator FI = RD->field_begin(),
+ FE = RD->field_end();
+ FI != FE; ++FI) {
+ QualType FieldType = Context.getBaseElementType(FI->getType());
+
+ // -- a non-static data member of reference type
+ if (FieldType->isReferenceType())
+ return true;
+
+ // -- a non-static data member of const non-class type (or array thereof)
+ if (FieldType.isConstQualified() && !FieldType->isRecordType())
+ return true;
+
+ CXXRecordDecl *FieldRecord = FieldType->getAsCXXRecordDecl();
+
+ if (FieldRecord) {
+ // This is an anonymous union
+ if (FieldRecord->isUnion() && FieldRecord->isAnonymousStructOrUnion()) {
+ // Anonymous unions inside unions do not variant members create
+ if (!Union) {
+ for (CXXRecordDecl::field_iterator UI = FieldRecord->field_begin(),
+ UE = FieldRecord->field_end();
+ UI != UE; ++UI) {
+ QualType UnionFieldType = Context.getBaseElementType(UI->getType());
+ CXXRecordDecl *UnionFieldRecord =
+ UnionFieldType->getAsCXXRecordDecl();
+
+ // -- a variant member with a non-trivial [copy] assignment operator
+ // and X is a union-like class
+ if (UnionFieldRecord &&
+ !UnionFieldRecord->hasTrivialCopyAssignment())
+ return true;
+ }
+ }
+
+ // Don't try to initalize an anonymous union
+ continue;
+ // -- a variant member with a non-trivial [copy] assignment operator
+ // and X is a union-like class
+ } else if (Union && !FieldRecord->hasTrivialCopyAssignment()) {
+ return true;
+ }
+
+ LookupQualifiedName(R, FieldRecord, false);
+
+ // Filter out any result that isn't a copy-assignment operator.
+ LookupResult::Filter F = R.makeFilter();
+ while (F.hasNext()) {
+ NamedDecl *D = F.next();
+ if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(D))
+ if (Method->isCopyAssignmentOperator())
+ continue;
+
+ F.erase();
+ }
+ F.done();
+
+ // Build a fake argument expression
+ QualType ArgType = FieldType;
+ QualType ThisType = FieldType;
+ if (ConstArg)
+ ArgType.addConst();
+ Expr *Args[] = { new (Context) OpaqueValueExpr(Loc, ThisType, VK_LValue)
+ , new (Context) OpaqueValueExpr(Loc, ArgType, VK_LValue)
+ };
+
+ OverloadCandidateSet OCS((Loc));
+ OverloadCandidateSet::iterator Best;
+
+ AddFunctionCandidates(R.asUnresolvedSet(), Args, 2, OCS);
+
+ if (OCS.BestViableFunction(*this, Loc, Best, false) !=
+ OR_Success)
+ return true;
+ }
+ }
+
+ return false;
+}
+
+bool Sema::ShouldDeleteDestructor(CXXDestructorDecl *DD) {
+ CXXRecordDecl *RD = DD->getParent();
+ assert(!RD->isDependentType() && "do deletion after instantiation");
+ if (!LangOpts.CPlusPlus0x)
+ return false;
+
+ SourceLocation Loc = DD->getLocation();
+
+ // Do access control from the destructor
+ ContextRAII CtorContext(*this, DD);
+
+ bool Union = RD->isUnion();
+
+ // We do this because we should never actually use an anonymous
+ // union's destructor.
+ if (Union && RD->isAnonymousStructOrUnion())
+ return false;
+
+ // C++0x [class.dtor]p5
+ // A defaulted destructor for a class X is defined as deleted if:
+ for (CXXRecordDecl::base_class_iterator BI = RD->bases_begin(),
+ BE = RD->bases_end();
+ BI != BE; ++BI) {
+ // We'll handle this one later
+ if (BI->isVirtual())
+ continue;
+
+ CXXRecordDecl *BaseDecl = BI->getType()->getAsCXXRecordDecl();
+ CXXDestructorDecl *BaseDtor = LookupDestructor(BaseDecl);
+ assert(BaseDtor && "base has no destructor");
+
+ // -- any direct or virtual base class has a deleted destructor or
+ // a destructor that is inaccessible from the defaulted destructor
+ if (BaseDtor->isDeleted())
+ return true;
+ if (CheckDestructorAccess(Loc, BaseDtor, PDiag()) !=
+ AR_accessible)
+ return true;
+ }
+
+ for (CXXRecordDecl::base_class_iterator BI = RD->vbases_begin(),
+ BE = RD->vbases_end();
+ BI != BE; ++BI) {
+ CXXRecordDecl *BaseDecl = BI->getType()->getAsCXXRecordDecl();
+ CXXDestructorDecl *BaseDtor = LookupDestructor(BaseDecl);
+ assert(BaseDtor && "base has no destructor");
+
+ // -- any direct or virtual base class has a deleted destructor or
+ // a destructor that is inaccessible from the defaulted destructor
+ if (BaseDtor->isDeleted())
+ return true;
+ if (CheckDestructorAccess(Loc, BaseDtor, PDiag()) !=
+ AR_accessible)
+ return true;
+ }
+
+ for (CXXRecordDecl::field_iterator FI = RD->field_begin(),
+ FE = RD->field_end();
+ FI != FE; ++FI) {
+ QualType FieldType = Context.getBaseElementType(FI->getType());
+ CXXRecordDecl *FieldRecord = FieldType->getAsCXXRecordDecl();
+ if (FieldRecord) {
+ if (FieldRecord->isUnion() && FieldRecord->isAnonymousStructOrUnion()) {
+ for (CXXRecordDecl::field_iterator UI = FieldRecord->field_begin(),
+ UE = FieldRecord->field_end();
+ UI != UE; ++UI) {
+ QualType UnionFieldType = Context.getBaseElementType(FI->getType());
+ CXXRecordDecl *UnionFieldRecord =
+ UnionFieldType->getAsCXXRecordDecl();
+
+ // -- X is a union-like class that has a variant member with a non-
+ // trivial destructor.
+ if (UnionFieldRecord && !UnionFieldRecord->hasTrivialDestructor())
+ return true;
+ }
+ // Technically we are supposed to do this next check unconditionally.
+ // But that makes absolutely no sense.
+ } else {
+ CXXDestructorDecl *FieldDtor = LookupDestructor(FieldRecord);
+
+ // -- any of the non-static data members has class type M (or array
+ // thereof) and M has a deleted destructor or a destructor that is
+ // inaccessible from the defaulted destructor
+ if (FieldDtor->isDeleted())
+ return true;
+ if (CheckDestructorAccess(Loc, FieldDtor, PDiag()) !=
+ AR_accessible)
+ return true;
+
+ // -- X is a union-like class that has a variant member with a non-
+ // trivial destructor.
+ if (Union && !FieldDtor->isTrivial())
+ return true;
+ }
+ }
+ }
+
+ if (DD->isVirtual()) {
+ FunctionDecl *OperatorDelete = 0;
+ DeclarationName Name =
+ Context.DeclarationNames.getCXXOperatorName(OO_Delete);
+ if (FindDeallocationFunction(Loc, RD, Name, OperatorDelete,
+ false))
+ return true;
+ }
+
+
+ return false;
}
/// \brief Data used with FindHiddenVirtualMethod
@@ -3053,113 +4169,6 @@ void Sema::ActOnFinishCXXMemberSpecification(Scope* S, SourceLocation RLoc,
dyn_cast_or_null<CXXRecordDecl>(TagDecl));
}
-namespace {
- /// \brief Helper class that collects exception specifications for
- /// implicitly-declared special member functions.
- class ImplicitExceptionSpecification {
- ASTContext &Context;
- // We order exception specifications thus:
- // noexcept is the most restrictive, but is only used in C++0x.
- // throw() comes next.
- // Then a throw(collected exceptions)
- // Finally no specification.
- // throw(...) is used instead if any called function uses it.
- ExceptionSpecificationType ComputedEST;
- llvm::SmallPtrSet<CanQualType, 4> ExceptionsSeen;
- llvm::SmallVector<QualType, 4> Exceptions;
-
- void ClearExceptions() {
- ExceptionsSeen.clear();
- Exceptions.clear();
- }
-
- public:
- explicit ImplicitExceptionSpecification(ASTContext &Context)
- : Context(Context), ComputedEST(EST_BasicNoexcept) {
- if (!Context.getLangOptions().CPlusPlus0x)
- ComputedEST = EST_DynamicNone;
- }
-
- /// \brief Get the computed exception specification type.
- ExceptionSpecificationType getExceptionSpecType() const {
- assert(ComputedEST != EST_ComputedNoexcept &&
- "noexcept(expr) should not be a possible result");
- return ComputedEST;
- }
-
- /// \brief The number of exceptions in the exception specification.
- unsigned size() const { return Exceptions.size(); }
-
- /// \brief The set of exceptions in the exception specification.
- const QualType *data() const { return Exceptions.data(); }
-
- /// \brief Integrate another called method into the collected data.
- void CalledDecl(CXXMethodDecl *Method) {
- // If we have an MSAny spec already, don't bother.
- if (!Method || ComputedEST == EST_MSAny)
- return;
-
- const FunctionProtoType *Proto
- = Method->getType()->getAs<FunctionProtoType>();
-
- ExceptionSpecificationType EST = Proto->getExceptionSpecType();
-
- // If this function can throw any exceptions, make a note of that.
- if (EST == EST_MSAny || EST == EST_None) {
- ClearExceptions();
- ComputedEST = EST;
- return;
- }
-
- // If this function has a basic noexcept, it doesn't affect the outcome.
- if (EST == EST_BasicNoexcept)
- return;
-
- // If we have a throw-all spec at this point, ignore the function.
- if (ComputedEST == EST_None)
- return;
-
- // If we're still at noexcept(true) and there's a nothrow() callee,
- // change to that specification.
- if (EST == EST_DynamicNone) {
- if (ComputedEST == EST_BasicNoexcept)
- ComputedEST = EST_DynamicNone;
- return;
- }
-
- // Check out noexcept specs.
- if (EST == EST_ComputedNoexcept) {
- FunctionProtoType::NoexceptResult NR = Proto->getNoexceptSpec(Context);
- assert(NR != FunctionProtoType::NR_NoNoexcept &&
- "Must have noexcept result for EST_ComputedNoexcept.");
- assert(NR != FunctionProtoType::NR_Dependent &&
- "Should not generate implicit declarations for dependent cases, "
- "and don't know how to handle them anyway.");
-
- // noexcept(false) -> no spec on the new function
- if (NR == FunctionProtoType::NR_Throw) {
- ClearExceptions();
- ComputedEST = EST_None;
- }
- // noexcept(true) won't change anything either.
- return;
- }
-
- assert(EST == EST_Dynamic && "EST case not considered earlier.");
- assert(ComputedEST != EST_None &&
- "Shouldn't collect exceptions when throw-all is guaranteed.");
- ComputedEST = EST_Dynamic;
- // Record the exceptions in this function's exception specification.
- for (FunctionProtoType::exception_iterator E = Proto->exception_begin(),
- EEnd = Proto->exception_end();
- E != EEnd; ++E)
- if (ExceptionsSeen.insert(Context.getCanonicalType(*E)))
- Exceptions.push_back(*E);
- }
- };
-}
-
-
/// AddImplicitlyDeclaredMembersToClass - Adds any implicitly-declared
/// special functions, such as the default constructor, copy
/// constructor, or destructor, to the given C++ class (C++
@@ -3467,6 +4476,11 @@ QualType Sema::CheckDestructorDeclarator(Declarator &D, QualType R,
if (const TypedefType *TT = DeclaratorType->getAs<TypedefType>())
Diag(D.getIdentifierLoc(), diag::err_destructor_typedef_name)
<< DeclaratorType << isa<TypeAliasDecl>(TT->getDecl());
+ else if (const TemplateSpecializationType *TST =
+ DeclaratorType->getAs<TemplateSpecializationType>())
+ if (TST->isTypeAlias())
+ Diag(D.getIdentifierLoc(), diag::err_destructor_typedef_name)
+ << DeclaratorType << 1;
// C++ [class.dtor]p2:
// A destructor is used to destroy objects of its class type. A
@@ -3725,18 +4739,37 @@ Decl *Sema::ActOnStartNamespaceDef(Scope *NamespcScope,
// treated as an original-namespace-name.
//
// Since namespace names are unique in their scope, and we don't
- // look through using directives, just
- DeclContext::lookup_result R = CurContext->getRedeclContext()->lookup(II);
- NamedDecl *PrevDecl = R.first == R.second? 0 : *R.first;
-
+ // look through using directives, just look for any ordinary names.
+
+ const unsigned IDNS = Decl::IDNS_Ordinary | Decl::IDNS_Member |
+ Decl::IDNS_Type | Decl::IDNS_Using | Decl::IDNS_Tag |
+ Decl::IDNS_Namespace;
+ NamedDecl *PrevDecl = 0;
+ for (DeclContext::lookup_result R
+ = CurContext->getRedeclContext()->lookup(II);
+ R.first != R.second; ++R.first) {
+ if ((*R.first)->getIdentifierNamespace() & IDNS) {
+ PrevDecl = *R.first;
+ break;
+ }
+ }
+
if (NamespaceDecl *OrigNS = dyn_cast_or_null<NamespaceDecl>(PrevDecl)) {
// This is an extended namespace definition.
if (Namespc->isInline() != OrigNS->isInline()) {
// inline-ness must match
- Diag(Namespc->getLocation(), diag::err_inline_namespace_mismatch)
- << Namespc->isInline();
+ if (OrigNS->isInline()) {
+ // The user probably just forgot the 'inline', so suggest that it
+ // be added back.
+ Diag(Namespc->getLocation(),
+ diag::warn_inline_namespace_reopened_noninline)
+ << FixItHint::CreateInsertion(NamespaceLoc, "inline ");
+ } else {
+ Diag(Namespc->getLocation(), diag::err_inline_namespace_mismatch)
+ << Namespc->isInline();
+ }
Diag(OrigNS->getLocation(), diag::note_previous_definition);
- Namespc->setInvalidDecl();
+
// Recover by ignoring the new namespace's inline status.
Namespc->setInline(OrigNS->isInline());
}
@@ -4408,6 +5441,7 @@ NamedDecl *Sema::BuildUsingDeclaration(Scope *S, AccessSpecifier AS,
// Otherwise, look up the target name.
LookupResult R(*this, NameInfo, LookupOrdinaryName);
+ R.setUsingDeclaration(true);
// Unlike most lookups, we don't always want to hide tag
// declarations: tag names are visible through the using declaration
@@ -4701,9 +5735,13 @@ bool Sema::CheckUsingDeclQualifier(SourceLocation UsingLoc,
Decl *Sema::ActOnAliasDeclaration(Scope *S,
AccessSpecifier AS,
+ MultiTemplateParamsArg TemplateParamLists,
SourceLocation UsingLoc,
UnqualifiedId &Name,
TypeResult Type) {
+ // Skip up to the relevant declaration scope.
+ while (S->getFlags() & Scope::TemplateParamScope)
+ S = S->getParent();
assert((S->getFlags() & Scope::DeclScope) &&
"got alias-declaration outside of declaration scope");
@@ -4719,8 +5757,11 @@ Decl *Sema::ActOnAliasDeclaration(Scope *S,
return 0;
if (DiagnoseUnexpandedParameterPack(Name.StartLocation, TInfo,
- UPPC_DeclarationType))
+ UPPC_DeclarationType)) {
Invalid = true;
+ TInfo = Context.getTrivialTypeSourceInfo(Context.IntTy,
+ TInfo->getTypeLoc().getBeginLoc());
+ }
LookupResult Previous(*this, NameInfo, LookupOrdinaryName, ForRedeclaration);
LookupName(Previous, S);
@@ -4745,13 +5786,93 @@ Decl *Sema::ActOnAliasDeclaration(Scope *S,
if (Invalid)
NewTD->setInvalidDecl();
+ CheckTypedefForVariablyModifiedType(S, NewTD);
+ Invalid |= NewTD->isInvalidDecl();
+
bool Redeclaration = false;
- ActOnTypedefNameDecl(S, CurContext, NewTD, Previous, Redeclaration);
+
+ NamedDecl *NewND;
+ if (TemplateParamLists.size()) {
+ TypeAliasTemplateDecl *OldDecl = 0;
+ TemplateParameterList *OldTemplateParams = 0;
+
+ if (TemplateParamLists.size() != 1) {
+ Diag(UsingLoc, diag::err_alias_template_extra_headers)
+ << SourceRange(TemplateParamLists.get()[1]->getTemplateLoc(),
+ TemplateParamLists.get()[TemplateParamLists.size()-1]->getRAngleLoc());
+ }
+ TemplateParameterList *TemplateParams = TemplateParamLists.get()[0];
+
+ // Only consider previous declarations in the same scope.
+ FilterLookupForScope(Previous, CurContext, S, /*ConsiderLinkage*/false,
+ /*ExplicitInstantiationOrSpecialization*/false);
+ if (!Previous.empty()) {
+ Redeclaration = true;
+
+ OldDecl = Previous.getAsSingle<TypeAliasTemplateDecl>();
+ if (!OldDecl && !Invalid) {
+ Diag(UsingLoc, diag::err_redefinition_different_kind)
+ << Name.Identifier;
+
+ NamedDecl *OldD = Previous.getRepresentativeDecl();
+ if (OldD->getLocation().isValid())
+ Diag(OldD->getLocation(), diag::note_previous_definition);
+
+ Invalid = true;
+ }
+
+ if (!Invalid && OldDecl && !OldDecl->isInvalidDecl()) {
+ if (TemplateParameterListsAreEqual(TemplateParams,
+ OldDecl->getTemplateParameters(),
+ /*Complain=*/true,
+ TPL_TemplateMatch))
+ OldTemplateParams = OldDecl->getTemplateParameters();
+ else
+ Invalid = true;
+
+ TypeAliasDecl *OldTD = OldDecl->getTemplatedDecl();
+ if (!Invalid &&
+ !Context.hasSameType(OldTD->getUnderlyingType(),
+ NewTD->getUnderlyingType())) {
+ // FIXME: The C++0x standard does not clearly say this is ill-formed,
+ // but we can't reasonably accept it.
+ Diag(NewTD->getLocation(), diag::err_redefinition_different_typedef)
+ << 2 << NewTD->getUnderlyingType() << OldTD->getUnderlyingType();
+ if (OldTD->getLocation().isValid())
+ Diag(OldTD->getLocation(), diag::note_previous_definition);
+ Invalid = true;
+ }
+ }
+ }
+
+ // Merge any previous default template arguments into our parameters,
+ // and check the parameter list.
+ if (CheckTemplateParameterList(TemplateParams, OldTemplateParams,
+ TPC_TypeAliasTemplate))
+ return 0;
+
+ TypeAliasTemplateDecl *NewDecl =
+ TypeAliasTemplateDecl::Create(Context, CurContext, UsingLoc,
+ Name.Identifier, TemplateParams,
+ NewTD);
+
+ NewDecl->setAccess(AS);
+
+ if (Invalid)
+ NewDecl->setInvalidDecl();
+ else if (OldDecl)
+ NewDecl->setPreviousDeclaration(OldDecl);
+
+ NewND = NewDecl;
+ } else {
+ ActOnTypedefNameDecl(S, CurContext, NewTD, Previous, Redeclaration);
+ NewND = NewTD;
+ }
if (!Redeclaration)
- PushOnScopeChains(NewTD, S);
+ PushOnScopeChains(NewND, S);
- return NewTD;
+ return NewND;
}
Decl *Sema::ActOnNamespaceAliasDef(Scope *S,
@@ -4855,39 +5976,8 @@ namespace {
};
}
-static CXXConstructorDecl *getDefaultConstructorUnsafe(Sema &Self,
- CXXRecordDecl *D) {
- ASTContext &Context = Self.Context;
- QualType ClassType = Context.getTypeDeclType(D);
- DeclarationName ConstructorName
- = Context.DeclarationNames.getCXXConstructorName(
- Context.getCanonicalType(ClassType.getUnqualifiedType()));
-
- DeclContext::lookup_const_iterator Con, ConEnd;
- for (llvm::tie(Con, ConEnd) = D->lookup(ConstructorName);
- Con != ConEnd; ++Con) {
- // FIXME: In C++0x, a constructor template can be a default constructor.
- if (isa<FunctionTemplateDecl>(*Con))
- continue;
-
- CXXConstructorDecl *Constructor = cast<CXXConstructorDecl>(*Con);
- if (Constructor->isDefaultConstructor())
- return Constructor;
- }
- return 0;
-}
-
-CXXConstructorDecl *Sema::DeclareImplicitDefaultConstructor(
- CXXRecordDecl *ClassDecl) {
- // C++ [class.ctor]p5:
- // A default constructor for a class X is a constructor of class X
- // that can be called without an argument. If there is no
- // user-declared constructor for class X, a default constructor is
- // implicitly declared. An implicitly-declared default constructor
- // is an inline public member of its class.
- assert(!ClassDecl->hasUserDeclaredConstructor() &&
- "Should not build implicit default constructor!");
-
+Sema::ImplicitExceptionSpecification
+Sema::ComputeDefaultedDefaultCtorExceptionSpec(CXXRecordDecl *ClassDecl) {
// C++ [except.spec]p14:
// An implicitly declared special member function (Clause 12) shall have an
// exception-specification. [...]
@@ -4902,10 +5992,10 @@ CXXConstructorDecl *Sema::DeclareImplicitDefaultConstructor(
if (const RecordType *BaseType = B->getType()->getAs<RecordType>()) {
CXXRecordDecl *BaseClassDecl = cast<CXXRecordDecl>(BaseType->getDecl());
- if (!BaseClassDecl->hasDeclaredDefaultConstructor())
- ExceptSpec.CalledDecl(DeclareImplicitDefaultConstructor(BaseClassDecl));
- else if (CXXConstructorDecl *Constructor
- = getDefaultConstructorUnsafe(*this, BaseClassDecl))
+ CXXConstructorDecl *Constructor = LookupDefaultConstructor(BaseClassDecl);
+ // If this is a deleted function, add it anyway. This might be conformant
+ // with the standard. This might not. I'm not sure. It might not matter.
+ if (Constructor)
ExceptSpec.CalledDecl(Constructor);
}
}
@@ -4916,10 +6006,10 @@ CXXConstructorDecl *Sema::DeclareImplicitDefaultConstructor(
B != BEnd; ++B) {
if (const RecordType *BaseType = B->getType()->getAs<RecordType>()) {
CXXRecordDecl *BaseClassDecl = cast<CXXRecordDecl>(BaseType->getDecl());
- if (!BaseClassDecl->hasDeclaredDefaultConstructor())
- ExceptSpec.CalledDecl(DeclareImplicitDefaultConstructor(BaseClassDecl));
- else if (CXXConstructorDecl *Constructor
- = getDefaultConstructorUnsafe(*this, BaseClassDecl))
+ CXXConstructorDecl *Constructor = LookupDefaultConstructor(BaseClassDecl);
+ // If this is a deleted function, add it anyway. This might be conformant
+ // with the standard. This might not. I'm not sure. It might not matter.
+ if (Constructor)
ExceptSpec.CalledDecl(Constructor);
}
}
@@ -4928,22 +6018,42 @@ CXXConstructorDecl *Sema::DeclareImplicitDefaultConstructor(
for (RecordDecl::field_iterator F = ClassDecl->field_begin(),
FEnd = ClassDecl->field_end();
F != FEnd; ++F) {
- if (const RecordType *RecordTy
+ if (F->hasInClassInitializer()) {
+ if (Expr *E = F->getInClassInitializer())
+ ExceptSpec.CalledExpr(E);
+ else if (!F->isInvalidDecl())
+ ExceptSpec.SetDelayed();
+ } else if (const RecordType *RecordTy
= Context.getBaseElementType(F->getType())->getAs<RecordType>()) {
- CXXRecordDecl *FieldClassDecl = cast<CXXRecordDecl>(RecordTy->getDecl());
- if (!FieldClassDecl->hasDeclaredDefaultConstructor())
- ExceptSpec.CalledDecl(
- DeclareImplicitDefaultConstructor(FieldClassDecl));
- else if (CXXConstructorDecl *Constructor
- = getDefaultConstructorUnsafe(*this, FieldClassDecl))
+ CXXRecordDecl *FieldRecDecl = cast<CXXRecordDecl>(RecordTy->getDecl());
+ CXXConstructorDecl *Constructor = LookupDefaultConstructor(FieldRecDecl);
+ // If this is a deleted function, add it anyway. This might be conformant
+ // with the standard. This might not. I'm not sure. It might not matter.
+ // In particular, the problem is that this function never gets called. It
+ // might just be ill-formed because this function attempts to refer to
+ // a deleted function here.
+ if (Constructor)
ExceptSpec.CalledDecl(Constructor);
}
}
- FunctionProtoType::ExtProtoInfo EPI;
- EPI.ExceptionSpecType = ExceptSpec.getExceptionSpecType();
- EPI.NumExceptions = ExceptSpec.size();
- EPI.Exceptions = ExceptSpec.data();
+ return ExceptSpec;
+}
+
+CXXConstructorDecl *Sema::DeclareImplicitDefaultConstructor(
+ CXXRecordDecl *ClassDecl) {
+ // C++ [class.ctor]p5:
+ // A default constructor for a class X is a constructor of class X
+ // that can be called without an argument. If there is no
+ // user-declared constructor for class X, a default constructor is
+ // implicitly declared. An implicitly-declared default constructor
+ // is an inline public member of its class.
+ assert(!ClassDecl->hasUserDeclaredConstructor() &&
+ "Should not build implicit default constructor!");
+
+ ImplicitExceptionSpecification Spec =
+ ComputeDefaultedDefaultCtorExceptionSpec(ClassDecl);
+ FunctionProtoType::ExtProtoInfo EPI = Spec.getEPI();
// Create the actual constructor declaration.
CanQualType ClassType
@@ -4961,8 +6071,9 @@ CXXConstructorDecl *Sema::DeclareImplicitDefaultConstructor(
/*isInline=*/true,
/*isImplicitlyDeclared=*/true);
DefaultCon->setAccess(AS_public);
+ DefaultCon->setDefaulted();
DefaultCon->setImplicit();
- DefaultCon->setTrivial(ClassDecl->hasTrivialConstructor());
+ DefaultCon->setTrivial(ClassDecl->hasTrivialDefaultConstructor());
// Note that we have declared this constructor.
++ASTContext::NumImplicitDefaultConstructorsDeclared;
@@ -4970,14 +6081,18 @@ CXXConstructorDecl *Sema::DeclareImplicitDefaultConstructor(
if (Scope *S = getScopeForContext(ClassDecl))
PushOnScopeChains(DefaultCon, S, false);
ClassDecl->addDecl(DefaultCon);
+
+ if (ShouldDeleteDefaultConstructor(DefaultCon))
+ DefaultCon->setDeletedAsWritten();
return DefaultCon;
}
void Sema::DefineImplicitDefaultConstructor(SourceLocation CurrentLocation,
CXXConstructorDecl *Constructor) {
- assert((Constructor->isImplicit() && Constructor->isDefaultConstructor() &&
- !Constructor->isUsed(false)) &&
+ assert((Constructor->isDefaulted() && Constructor->isDefaultConstructor() &&
+ !Constructor->doesThisDeclarationHaveABody() &&
+ !Constructor->isDeleted()) &&
"DefineImplicitDefaultConstructor - call it for implicit default ctor");
CXXRecordDecl *ClassDecl = Constructor->getParent();
@@ -4988,7 +6103,7 @@ void Sema::DefineImplicitDefaultConstructor(SourceLocation CurrentLocation,
if (SetCtorInitializers(Constructor, 0, 0, /*AnyErrors=*/false) ||
Trap.hasErrorOccurred()) {
Diag(CurrentLocation, diag::note_member_synthesized_at)
- << CXXConstructor << Context.getTagDeclType(ClassDecl);
+ << CXXDefaultConstructor << Context.getTagDeclType(ClassDecl);
Constructor->setInvalidDecl();
return;
}
@@ -5004,6 +6119,59 @@ void Sema::DefineImplicitDefaultConstructor(SourceLocation CurrentLocation,
}
}
+/// Get any existing defaulted default constructor for the given class. Do not
+/// implicitly define one if it does not exist.
+static CXXConstructorDecl *getDefaultedDefaultConstructorUnsafe(Sema &Self,
+ CXXRecordDecl *D) {
+ ASTContext &Context = Self.Context;
+ QualType ClassType = Context.getTypeDeclType(D);
+ DeclarationName ConstructorName
+ = Context.DeclarationNames.getCXXConstructorName(
+ Context.getCanonicalType(ClassType.getUnqualifiedType()));
+
+ DeclContext::lookup_const_iterator Con, ConEnd;
+ for (llvm::tie(Con, ConEnd) = D->lookup(ConstructorName);
+ Con != ConEnd; ++Con) {
+ // A function template cannot be defaulted.
+ if (isa<FunctionTemplateDecl>(*Con))
+ continue;
+
+ CXXConstructorDecl *Constructor = cast<CXXConstructorDecl>(*Con);
+ if (Constructor->isDefaultConstructor())
+ return Constructor->isDefaulted() ? Constructor : 0;
+ }
+ return 0;
+}
+
+void Sema::ActOnFinishDelayedMemberInitializers(Decl *D) {
+ if (!D) return;
+ AdjustDeclIfTemplate(D);
+
+ CXXRecordDecl *ClassDecl = cast<CXXRecordDecl>(D);
+ CXXConstructorDecl *CtorDecl
+ = getDefaultedDefaultConstructorUnsafe(*this, ClassDecl);
+
+ if (!CtorDecl) return;
+
+ // Compute the exception specification for the default constructor.
+ const FunctionProtoType *CtorTy =
+ CtorDecl->getType()->castAs<FunctionProtoType>();
+ if (CtorTy->getExceptionSpecType() == EST_Delayed) {
+ ImplicitExceptionSpecification Spec =
+ ComputeDefaultedDefaultCtorExceptionSpec(ClassDecl);
+ FunctionProtoType::ExtProtoInfo EPI = Spec.getEPI();
+ assert(EPI.ExceptionSpecType != EST_Delayed);
+
+ CtorDecl->setType(Context.getFunctionType(Context.VoidTy, 0, 0, EPI));
+ }
+
+ // If the default constructor is explicitly defaulted, checking the exception
+ // specification is deferred until now.
+ if (!CtorDecl->isInvalidDecl() && CtorDecl->isExplicitlyDefaulted() &&
+ !ClassDecl->isDependentType())
+ CheckExplicitlyDefaultedDefaultConstructor(CtorDecl);
+}
+
void Sema::DeclareInheritedConstructors(CXXRecordDecl *ClassDecl) {
// We start with an initial pass over the base classes to collect those that
// inherit constructors from. If there are none, we can forgo all further
@@ -5097,7 +6265,9 @@ void Sema::DeclareInheritedConstructors(CXXRecordDecl *ClassDecl) {
// Build up a function type for this particular constructor.
// FIXME: The working paper does not consider that the exception spec
// for the inheriting constructor might be larger than that of the
- // source. This code doesn't yet, either.
+ // source. This code doesn't yet, either. When it does, this code will
+ // need to be delayed until after exception specifications and in-class
+ // member initializers are attached.
const Type *NewCtorType;
if (params == maxParams)
NewCtorType = BaseCtorType;
@@ -5179,12 +6349,8 @@ void Sema::DeclareInheritedConstructors(CXXRecordDecl *ClassDecl) {
}
}
-CXXDestructorDecl *Sema::DeclareImplicitDestructor(CXXRecordDecl *ClassDecl) {
- // C++ [class.dtor]p2:
- // If a class has no user-declared destructor, a destructor is
- // declared implicitly. An implicitly-declared destructor is an
- // inline public member of its class.
-
+Sema::ImplicitExceptionSpecification
+Sema::ComputeDefaultedDtorExceptionSpec(CXXRecordDecl *ClassDecl) {
// C++ [except.spec]p14:
// An implicitly declared special member function (Clause 12) shall have
// an exception-specification.
@@ -5199,18 +6365,18 @@ CXXDestructorDecl *Sema::DeclareImplicitDestructor(CXXRecordDecl *ClassDecl) {
if (const RecordType *BaseType = B->getType()->getAs<RecordType>())
ExceptSpec.CalledDecl(
- LookupDestructor(cast<CXXRecordDecl>(BaseType->getDecl())));
+ LookupDestructor(cast<CXXRecordDecl>(BaseType->getDecl())));
}
-
+
// Virtual base-class destructors.
for (CXXRecordDecl::base_class_iterator B = ClassDecl->vbases_begin(),
BEnd = ClassDecl->vbases_end();
B != BEnd; ++B) {
if (const RecordType *BaseType = B->getType()->getAs<RecordType>())
ExceptSpec.CalledDecl(
- LookupDestructor(cast<CXXRecordDecl>(BaseType->getDecl())));
+ LookupDestructor(cast<CXXRecordDecl>(BaseType->getDecl())));
}
-
+
// Field destructors.
for (RecordDecl::field_iterator F = ClassDecl->field_begin(),
FEnd = ClassDecl->field_end();
@@ -5218,14 +6384,23 @@ CXXDestructorDecl *Sema::DeclareImplicitDestructor(CXXRecordDecl *ClassDecl) {
if (const RecordType *RecordTy
= Context.getBaseElementType(F->getType())->getAs<RecordType>())
ExceptSpec.CalledDecl(
- LookupDestructor(cast<CXXRecordDecl>(RecordTy->getDecl())));
+ LookupDestructor(cast<CXXRecordDecl>(RecordTy->getDecl())));
}
+ return ExceptSpec;
+}
+
+CXXDestructorDecl *Sema::DeclareImplicitDestructor(CXXRecordDecl *ClassDecl) {
+ // C++ [class.dtor]p2:
+ // If a class has no user-declared destructor, a destructor is
+ // declared implicitly. An implicitly-declared destructor is an
+ // inline public member of its class.
+
+ ImplicitExceptionSpecification Spec =
+ ComputeDefaultedDtorExceptionSpec(ClassDecl);
+ FunctionProtoType::ExtProtoInfo EPI = Spec.getEPI();
+
// Create the actual destructor declaration.
- FunctionProtoType::ExtProtoInfo EPI;
- EPI.ExceptionSpecType = ExceptSpec.getExceptionSpecType();
- EPI.NumExceptions = ExceptSpec.size();
- EPI.Exceptions = ExceptSpec.data();
QualType Ty = Context.getFunctionType(Context.VoidTy, 0, 0, EPI);
CanQualType ClassType
@@ -5239,6 +6414,7 @@ CXXDestructorDecl *Sema::DeclareImplicitDestructor(CXXRecordDecl *ClassDecl) {
/*isInline=*/true,
/*isImplicitlyDeclared=*/true);
Destructor->setAccess(AS_public);
+ Destructor->setDefaulted();
Destructor->setImplicit();
Destructor->setTrivial(ClassDecl->hasTrivialDestructor());
@@ -5252,6 +6428,9 @@ CXXDestructorDecl *Sema::DeclareImplicitDestructor(CXXRecordDecl *ClassDecl) {
// This could be uniqued if it ever proves significant.
Destructor->setTypeSourceInfo(Context.getTrivialTypeSourceInfo(Ty));
+
+ if (ShouldDeleteDestructor(Destructor))
+ Destructor->setDeletedAsWritten();
AddOverriddenMethods(ClassDecl, Destructor);
@@ -5260,7 +6439,8 @@ CXXDestructorDecl *Sema::DeclareImplicitDestructor(CXXRecordDecl *ClassDecl) {
void Sema::DefineImplicitDestructor(SourceLocation CurrentLocation,
CXXDestructorDecl *Destructor) {
- assert((Destructor->isImplicit() && !Destructor->isUsed(false)) &&
+ assert((Destructor->isDefaulted() &&
+ !Destructor->doesThisDeclarationHaveABody()) &&
"DefineImplicitDestructor - call it for implicit default dtor");
CXXRecordDecl *ClassDecl = Destructor->getParent();
assert(ClassDecl && "DefineImplicitDestructor - invalid destructor");
@@ -5293,6 +6473,35 @@ void Sema::DefineImplicitDestructor(SourceLocation CurrentLocation,
}
}
+void Sema::AdjustDestructorExceptionSpec(CXXRecordDecl *classDecl,
+ CXXDestructorDecl *destructor) {
+ // C++11 [class.dtor]p3:
+ // A declaration of a destructor that does not have an exception-
+ // specification is implicitly considered to have the same exception-
+ // specification as an implicit declaration.
+ const FunctionProtoType *dtorType = destructor->getType()->
+ getAs<FunctionProtoType>();
+ if (dtorType->hasExceptionSpec())
+ return;
+
+ ImplicitExceptionSpecification exceptSpec =
+ ComputeDefaultedDtorExceptionSpec(classDecl);
+
+ // Replace the destructor's type.
+ FunctionProtoType::ExtProtoInfo epi;
+ epi.ExceptionSpecType = exceptSpec.getExceptionSpecType();
+ epi.NumExceptions = exceptSpec.size();
+ epi.Exceptions = exceptSpec.data();
+ QualType ty = Context.getFunctionType(Context.VoidTy, 0, 0, epi);
+
+ destructor->setType(ty);
+
+ // FIXME: If the destructor has a body that could throw, and the newly created
+ // spec doesn't allow exceptions, we should emit a warning, because this
+ // change in behavior can break conforming C++03 programs at runtime.
+ // However, we don't have a body yet, so it needs to be done somewhere else.
+}
+
/// \brief Builds a statement that copies the given entity from \p From to
/// \c To.
///
@@ -5530,13 +6739,9 @@ static bool hasConstCopyAssignment(Sema &S, const CXXRecordDecl *CClass) {
return false;
}
-CXXMethodDecl *Sema::DeclareImplicitCopyAssignment(CXXRecordDecl *ClassDecl) {
- // Note: The following rules are largely analoguous to the copy
- // constructor rules. Note that virtual bases are not taken into account
- // for determining the argument type of the operator. Note also that
- // operators taking an object instead of a reference are allowed.
-
-
+std::pair<Sema::ImplicitExceptionSpecification, bool>
+Sema::ComputeDefaultedCopyAssignmentExceptionSpecAndConst(
+ CXXRecordDecl *ClassDecl) {
// C++ [class.copy]p10:
// If the class definition does not explicitly declare a copy
// assignment operator, one is declared implicitly.
@@ -5581,11 +6786,6 @@ CXXMethodDecl *Sema::DeclareImplicitCopyAssignment(CXXRecordDecl *ClassDecl) {
// have the form
//
// X& X::operator=(X&)
- QualType ArgType = Context.getTypeDeclType(ClassDecl);
- QualType RetType = Context.getLValueReferenceType(ArgType);
- if (HasConstCopyAssignment)
- ArgType = ArgType.withConst();
- ArgType = Context.getLValueReferenceType(ArgType);
// C++ [except.spec]p14:
// An implicitly declared special member function (Clause 12) shall have an
@@ -5622,12 +6822,29 @@ CXXMethodDecl *Sema::DeclareImplicitCopyAssignment(CXXRecordDecl *ClassDecl) {
}
}
+ return std::make_pair(ExceptSpec, HasConstCopyAssignment);
+}
+
+CXXMethodDecl *Sema::DeclareImplicitCopyAssignment(CXXRecordDecl *ClassDecl) {
+ // Note: The following rules are largely analoguous to the copy
+ // constructor rules. Note that virtual bases are not taken into account
+ // for determining the argument type of the operator. Note also that
+ // operators taking an object instead of a reference are allowed.
+
+ ImplicitExceptionSpecification Spec(Context);
+ bool Const;
+ llvm::tie(Spec, Const) =
+ ComputeDefaultedCopyAssignmentExceptionSpecAndConst(ClassDecl);
+
+ QualType ArgType = Context.getTypeDeclType(ClassDecl);
+ QualType RetType = Context.getLValueReferenceType(ArgType);
+ if (Const)
+ ArgType = ArgType.withConst();
+ ArgType = Context.getLValueReferenceType(ArgType);
+
// An implicitly-declared copy assignment operator is an inline public
// member of its class.
- FunctionProtoType::ExtProtoInfo EPI;
- EPI.ExceptionSpecType = ExceptSpec.getExceptionSpecType();
- EPI.NumExceptions = ExceptSpec.size();
- EPI.Exceptions = ExceptSpec.data();
+ FunctionProtoType::ExtProtoInfo EPI = Spec.getEPI();
DeclarationName Name = Context.DeclarationNames.getCXXOperatorName(OO_Equal);
SourceLocation ClassLoc = ClassDecl->getLocation();
DeclarationNameInfo NameInfo(Name, ClassLoc);
@@ -5639,6 +6856,7 @@ CXXMethodDecl *Sema::DeclareImplicitCopyAssignment(CXXRecordDecl *ClassDecl) {
/*isInline=*/true,
SourceLocation());
CopyAssignment->setAccess(AS_public);
+ CopyAssignment->setDefaulted();
CopyAssignment->setImplicit();
CopyAssignment->setTrivial(ClassDecl->hasTrivialCopyAssignment());
@@ -5652,21 +6870,24 @@ CXXMethodDecl *Sema::DeclareImplicitCopyAssignment(CXXRecordDecl *ClassDecl) {
// Note that we have added this copy-assignment operator.
++ASTContext::NumImplicitCopyAssignmentOperatorsDeclared;
-
+
if (Scope *S = getScopeForContext(ClassDecl))
PushOnScopeChains(CopyAssignment, S, false);
ClassDecl->addDecl(CopyAssignment);
+ if (ShouldDeleteCopyAssignmentOperator(CopyAssignment))
+ CopyAssignment->setDeletedAsWritten();
+
AddOverriddenMethods(ClassDecl, CopyAssignment);
return CopyAssignment;
}
void Sema::DefineImplicitCopyAssignment(SourceLocation CurrentLocation,
CXXMethodDecl *CopyAssignOperator) {
- assert((CopyAssignOperator->isImplicit() &&
+ assert((CopyAssignOperator->isDefaulted() &&
CopyAssignOperator->isOverloadedOperator() &&
CopyAssignOperator->getOverloadedOperator() == OO_Equal &&
- !CopyAssignOperator->isUsed(false)) &&
+ !CopyAssignOperator->doesThisDeclarationHaveABody()) &&
"DefineImplicitCopyAssignment called for wrong function");
CXXRecordDecl *ClassDecl = CopyAssignOperator->getParent();
@@ -5956,12 +7177,8 @@ void Sema::DefineImplicitCopyAssignment(SourceLocation CurrentLocation,
}
}
-CXXConstructorDecl *Sema::DeclareImplicitCopyConstructor(
- CXXRecordDecl *ClassDecl) {
- // C++ [class.copy]p4:
- // If the class definition does not explicitly declare a copy
- // constructor, one is declared implicitly.
-
+std::pair<Sema::ImplicitExceptionSpecification, bool>
+Sema::ComputeDefaultedCopyCtorExceptionSpecAndConst(CXXRecordDecl *ClassDecl) {
// C++ [class.copy]p5:
// The implicitly-declared copy constructor for a class X will
// have the form
@@ -5969,6 +7186,7 @@ CXXConstructorDecl *Sema::DeclareImplicitCopyConstructor(
// X::X(const X&)
//
// if
+ // FIXME: It ought to be possible to store this on the record.
bool HasConstCopyConstructor = true;
// -- each direct or virtual base class B of X has a copy
@@ -5984,11 +7202,8 @@ CXXConstructorDecl *Sema::DeclareImplicitCopyConstructor(
CXXRecordDecl *BaseClassDecl
= cast<CXXRecordDecl>(Base->getType()->getAs<RecordType>()->getDecl());
- if (!BaseClassDecl->hasDeclaredCopyConstructor())
- DeclareImplicitCopyConstructor(BaseClassDecl);
-
- HasConstCopyConstructor
- = BaseClassDecl->hasConstCopyConstructor(Context);
+ LookupCopyConstructor(BaseClassDecl, Qualifiers::Const,
+ &HasConstCopyConstructor);
}
for (CXXRecordDecl::base_class_iterator Base = ClassDecl->vbases_begin(),
@@ -5997,11 +7212,8 @@ CXXConstructorDecl *Sema::DeclareImplicitCopyConstructor(
++Base) {
CXXRecordDecl *BaseClassDecl
= cast<CXXRecordDecl>(Base->getType()->getAs<RecordType>()->getDecl());
- if (!BaseClassDecl->hasDeclaredCopyConstructor())
- DeclareImplicitCopyConstructor(BaseClassDecl);
-
- HasConstCopyConstructor
- = BaseClassDecl->hasConstCopyConstructor(Context);
+ LookupCopyConstructor(BaseClassDecl, Qualifiers::Const,
+ &HasConstCopyConstructor);
}
// -- for all the nonstatic data members of X that are of a
@@ -6013,27 +7225,16 @@ CXXConstructorDecl *Sema::DeclareImplicitCopyConstructor(
HasConstCopyConstructor && Field != FieldEnd;
++Field) {
QualType FieldType = Context.getBaseElementType((*Field)->getType());
- if (const RecordType *FieldClassType = FieldType->getAs<RecordType>()) {
- CXXRecordDecl *FieldClassDecl
- = cast<CXXRecordDecl>(FieldClassType->getDecl());
- if (!FieldClassDecl->hasDeclaredCopyConstructor())
- DeclareImplicitCopyConstructor(FieldClassDecl);
-
- HasConstCopyConstructor
- = FieldClassDecl->hasConstCopyConstructor(Context);
+ if (CXXRecordDecl *FieldClassDecl = FieldType->getAsCXXRecordDecl()) {
+ LookupCopyConstructor(FieldClassDecl, Qualifiers::Const,
+ &HasConstCopyConstructor);
}
}
-
// Otherwise, the implicitly declared copy constructor will have
// the form
//
// X::X(X&)
- QualType ClassType = Context.getTypeDeclType(ClassDecl);
- QualType ArgType = ClassType;
- if (HasConstCopyConstructor)
- ArgType = ArgType.withConst();
- ArgType = Context.getLValueReferenceType(ArgType);
-
+
// C++ [except.spec]p14:
// An implicitly declared special member function (Clause 12) shall have an
// exception-specification. [...]
@@ -6049,11 +7250,8 @@ CXXConstructorDecl *Sema::DeclareImplicitCopyConstructor(
CXXRecordDecl *BaseClassDecl
= cast<CXXRecordDecl>(Base->getType()->getAs<RecordType>()->getDecl());
- if (!BaseClassDecl->hasDeclaredCopyConstructor())
- DeclareImplicitCopyConstructor(BaseClassDecl);
-
- if (CXXConstructorDecl *CopyConstructor
- = BaseClassDecl->getCopyConstructor(Context, Quals))
+ if (CXXConstructorDecl *CopyConstructor =
+ LookupCopyConstructor(BaseClassDecl, Quals))
ExceptSpec.CalledDecl(CopyConstructor);
}
for (CXXRecordDecl::base_class_iterator Base = ClassDecl->vbases_begin(),
@@ -6062,11 +7260,8 @@ CXXConstructorDecl *Sema::DeclareImplicitCopyConstructor(
++Base) {
CXXRecordDecl *BaseClassDecl
= cast<CXXRecordDecl>(Base->getType()->getAs<RecordType>()->getDecl());
- if (!BaseClassDecl->hasDeclaredCopyConstructor())
- DeclareImplicitCopyConstructor(BaseClassDecl);
-
- if (CXXConstructorDecl *CopyConstructor
- = BaseClassDecl->getCopyConstructor(Context, Quals))
+ if (CXXConstructorDecl *CopyConstructor =
+ LookupCopyConstructor(BaseClassDecl, Quals))
ExceptSpec.CalledDecl(CopyConstructor);
}
for (CXXRecordDecl::field_iterator Field = ClassDecl->field_begin(),
@@ -6074,29 +7269,43 @@ CXXConstructorDecl *Sema::DeclareImplicitCopyConstructor(
Field != FieldEnd;
++Field) {
QualType FieldType = Context.getBaseElementType((*Field)->getType());
- if (const RecordType *FieldClassType = FieldType->getAs<RecordType>()) {
- CXXRecordDecl *FieldClassDecl
- = cast<CXXRecordDecl>(FieldClassType->getDecl());
- if (!FieldClassDecl->hasDeclaredCopyConstructor())
- DeclareImplicitCopyConstructor(FieldClassDecl);
-
- if (CXXConstructorDecl *CopyConstructor
- = FieldClassDecl->getCopyConstructor(Context, Quals))
- ExceptSpec.CalledDecl(CopyConstructor);
+ if (CXXRecordDecl *FieldClassDecl = FieldType->getAsCXXRecordDecl()) {
+ if (CXXConstructorDecl *CopyConstructor =
+ LookupCopyConstructor(FieldClassDecl, Quals))
+ ExceptSpec.CalledDecl(CopyConstructor);
}
}
- // An implicitly-declared copy constructor is an inline public
- // member of its class.
- FunctionProtoType::ExtProtoInfo EPI;
- EPI.ExceptionSpecType = ExceptSpec.getExceptionSpecType();
- EPI.NumExceptions = ExceptSpec.size();
- EPI.Exceptions = ExceptSpec.data();
+ return std::make_pair(ExceptSpec, HasConstCopyConstructor);
+}
+
+CXXConstructorDecl *Sema::DeclareImplicitCopyConstructor(
+ CXXRecordDecl *ClassDecl) {
+ // C++ [class.copy]p4:
+ // If the class definition does not explicitly declare a copy
+ // constructor, one is declared implicitly.
+
+ ImplicitExceptionSpecification Spec(Context);
+ bool Const;
+ llvm::tie(Spec, Const) =
+ ComputeDefaultedCopyCtorExceptionSpecAndConst(ClassDecl);
+
+ QualType ClassType = Context.getTypeDeclType(ClassDecl);
+ QualType ArgType = ClassType;
+ if (Const)
+ ArgType = ArgType.withConst();
+ ArgType = Context.getLValueReferenceType(ArgType);
+
+ FunctionProtoType::ExtProtoInfo EPI = Spec.getEPI();
+
DeclarationName Name
= Context.DeclarationNames.getCXXConstructorName(
Context.getCanonicalType(ClassType));
SourceLocation ClassLoc = ClassDecl->getLocation();
DeclarationNameInfo NameInfo(Name, ClassLoc);
+
+ // An implicitly-declared copy constructor is an inline public
+ // member of its class.
CXXConstructorDecl *CopyConstructor
= CXXConstructorDecl::Create(Context, ClassDecl, ClassLoc, NameInfo,
Context.getFunctionType(Context.VoidTy,
@@ -6106,6 +7315,7 @@ CXXConstructorDecl *Sema::DeclareImplicitCopyConstructor(
/*isInline=*/true,
/*isImplicitlyDeclared=*/true);
CopyConstructor->setAccess(AS_public);
+ CopyConstructor->setDefaulted();
CopyConstructor->setTrivial(ClassDecl->hasTrivialCopyConstructor());
// Note that we have declared this constructor.
@@ -6119,19 +7329,22 @@ CXXConstructorDecl *Sema::DeclareImplicitCopyConstructor(
SC_None,
SC_None, 0);
CopyConstructor->setParams(&FromParam, 1);
+
if (Scope *S = getScopeForContext(ClassDecl))
PushOnScopeChains(CopyConstructor, S, false);
ClassDecl->addDecl(CopyConstructor);
+
+ if (ShouldDeleteCopyConstructor(CopyConstructor))
+ CopyConstructor->setDeletedAsWritten();
return CopyConstructor;
}
void Sema::DefineImplicitCopyConstructor(SourceLocation CurrentLocation,
- CXXConstructorDecl *CopyConstructor,
- unsigned TypeQuals) {
- assert((CopyConstructor->isImplicit() &&
- CopyConstructor->isCopyConstructor(TypeQuals) &&
- !CopyConstructor->isUsed(false)) &&
+ CXXConstructorDecl *CopyConstructor) {
+ assert((CopyConstructor->isDefaulted() &&
+ CopyConstructor->isCopyConstructor() &&
+ !CopyConstructor->doesThisDeclarationHaveABody()) &&
"DefineImplicitCopyConstructor - call it for implicit copy ctor");
CXXRecordDecl *ClassDecl = CopyConstructor->getParent();
@@ -7138,7 +8351,7 @@ Decl *Sema::ActOnTemplatedFriendTag(Scope *S, SourceLocation FriendLoc,
bool Invalid = false;
if (TemplateParameterList *TemplateParams
- = MatchTemplateParametersToScopeSpecifier(TagLoc, SS,
+ = MatchTemplateParametersToScopeSpecifier(TagLoc, NameLoc, SS,
TempParamLists.get(),
TempParamLists.size(),
/*friend*/ true,
@@ -7554,7 +8767,83 @@ void Sema::SetDeclDeleted(Decl *Dcl, SourceLocation DelLoc) {
// If the declaration wasn't the first, we delete the function anyway for
// recovery.
}
- Fn->setDeleted();
+ Fn->setDeletedAsWritten();
+}
+
+void Sema::SetDeclDefaulted(Decl *Dcl, SourceLocation DefaultLoc) {
+ CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(Dcl);
+
+ if (MD) {
+ if (MD->getParent()->isDependentType()) {
+ MD->setDefaulted();
+ MD->setExplicitlyDefaulted();
+ return;
+ }
+
+ CXXSpecialMember Member = getSpecialMember(MD);
+ if (Member == CXXInvalid) {
+ Diag(DefaultLoc, diag::err_default_special_members);
+ return;
+ }
+
+ MD->setDefaulted();
+ MD->setExplicitlyDefaulted();
+
+ // If this definition appears within the record, do the checking when
+ // the record is complete.
+ const FunctionDecl *Primary = MD;
+ if (MD->getTemplatedKind() != FunctionDecl::TK_NonTemplate)
+ // Find the uninstantiated declaration that actually had the '= default'
+ // on it.
+ MD->getTemplateInstantiationPattern()->isDefined(Primary);
+
+ if (Primary == Primary->getCanonicalDecl())
+ return;
+
+ switch (Member) {
+ case CXXDefaultConstructor: {
+ CXXConstructorDecl *CD = cast<CXXConstructorDecl>(MD);
+ CheckExplicitlyDefaultedDefaultConstructor(CD);
+ if (!CD->isInvalidDecl())
+ DefineImplicitDefaultConstructor(DefaultLoc, CD);
+ break;
+ }
+
+ case CXXCopyConstructor: {
+ CXXConstructorDecl *CD = cast<CXXConstructorDecl>(MD);
+ CheckExplicitlyDefaultedCopyConstructor(CD);
+ if (!CD->isInvalidDecl())
+ DefineImplicitCopyConstructor(DefaultLoc, CD);
+ break;
+ }
+
+ case CXXCopyAssignment: {
+ CheckExplicitlyDefaultedCopyAssignment(MD);
+ if (!MD->isInvalidDecl())
+ DefineImplicitCopyAssignment(DefaultLoc, MD);
+ break;
+ }
+
+ case CXXDestructor: {
+ CXXDestructorDecl *DD = cast<CXXDestructorDecl>(MD);
+ CheckExplicitlyDefaultedDestructor(DD);
+ if (!DD->isInvalidDecl())
+ DefineImplicitDestructor(DefaultLoc, DD);
+ break;
+ }
+
+ case CXXMoveConstructor:
+ case CXXMoveAssignment:
+ Diag(Dcl->getLocation(), diag::err_defaulted_move_unsupported);
+ break;
+
+ default:
+ // FIXME: Do the rest once we have move functions
+ break;
+ }
+ } else {
+ Diag(DefaultLoc, diag::err_default_special_members);
+ }
}
static void SearchForReturnInStmt(Sema &Self, Stmt *S) {
@@ -7946,3 +9235,86 @@ void Sema::SetIvarInitializers(ObjCImplementationDecl *ObjCImplementation) {
AllToInit.data(), AllToInit.size());
}
}
+
+static
+void DelegatingCycleHelper(CXXConstructorDecl* Ctor,
+ llvm::SmallSet<CXXConstructorDecl*, 4> &Valid,
+ llvm::SmallSet<CXXConstructorDecl*, 4> &Invalid,
+ llvm::SmallSet<CXXConstructorDecl*, 4> &Current,
+ Sema &S) {
+ llvm::SmallSet<CXXConstructorDecl*, 4>::iterator CI = Current.begin(),
+ CE = Current.end();
+ if (Ctor->isInvalidDecl())
+ return;
+
+ const FunctionDecl *FNTarget = 0;
+ CXXConstructorDecl *Target;
+
+ // We ignore the result here since if we don't have a body, Target will be
+ // null below.
+ (void)Ctor->getTargetConstructor()->hasBody(FNTarget);
+ Target
+= const_cast<CXXConstructorDecl*>(cast_or_null<CXXConstructorDecl>(FNTarget));
+
+ CXXConstructorDecl *Canonical = Ctor->getCanonicalDecl(),
+ // Avoid dereferencing a null pointer here.
+ *TCanonical = Target ? Target->getCanonicalDecl() : 0;
+
+ if (!Current.insert(Canonical))
+ return;
+
+ // We know that beyond here, we aren't chaining into a cycle.
+ if (!Target || !Target->isDelegatingConstructor() ||
+ Target->isInvalidDecl() || Valid.count(TCanonical)) {
+ for (CI = Current.begin(), CE = Current.end(); CI != CE; ++CI)
+ Valid.insert(*CI);
+ Current.clear();
+ // We've hit a cycle.
+ } else if (TCanonical == Canonical || Invalid.count(TCanonical) ||
+ Current.count(TCanonical)) {
+ // If we haven't diagnosed this cycle yet, do so now.
+ if (!Invalid.count(TCanonical)) {
+ S.Diag((*Ctor->init_begin())->getSourceLocation(),
+ diag::warn_delegating_ctor_cycle)
+ << Ctor;
+
+ // Don't add a note for a function delegating directo to itself.
+ if (TCanonical != Canonical)
+ S.Diag(Target->getLocation(), diag::note_it_delegates_to);
+
+ CXXConstructorDecl *C = Target;
+ while (C->getCanonicalDecl() != Canonical) {
+ (void)C->getTargetConstructor()->hasBody(FNTarget);
+ assert(FNTarget && "Ctor cycle through bodiless function");
+
+ C
+ = const_cast<CXXConstructorDecl*>(cast<CXXConstructorDecl>(FNTarget));
+ S.Diag(C->getLocation(), diag::note_which_delegates_to);
+ }
+ }
+
+ for (CI = Current.begin(), CE = Current.end(); CI != CE; ++CI)
+ Invalid.insert(*CI);
+ Current.clear();
+ } else {
+ DelegatingCycleHelper(Target, Valid, Invalid, Current, S);
+ }
+}
+
+
+void Sema::CheckDelegatingCtorCycles() {
+ llvm::SmallSet<CXXConstructorDecl*, 4> Valid, Invalid, Current;
+
+ llvm::SmallSet<CXXConstructorDecl*, 4>::iterator CI = Current.begin(),
+ CE = Current.end();
+
+ for (llvm::SmallVector<CXXConstructorDecl*, 4>::iterator
+ I = DelegatingCtorDecls.begin(),
+ E = DelegatingCtorDecls.end();
+ I != E; ++I) {
+ DelegatingCycleHelper(*I, Valid, Invalid, Current, *this);
+ }
+
+ for (CI = Invalid.begin(), CE = Invalid.end(); CI != CE; ++CI)
+ (*CI)->setInvalidDecl();
+}
diff --git a/lib/Sema/SemaDeclObjC.cpp b/lib/Sema/SemaDeclObjC.cpp
index 7b235ba..de9097e 100644
--- a/lib/Sema/SemaDeclObjC.cpp
+++ b/lib/Sema/SemaDeclObjC.cpp
@@ -24,6 +24,141 @@
using namespace clang;
+bool Sema::CheckObjCMethodOverride(ObjCMethodDecl *NewMethod,
+ const ObjCMethodDecl *Overridden,
+ bool IsImplementation) {
+ if (Overridden->hasRelatedResultType() &&
+ !NewMethod->hasRelatedResultType()) {
+ // This can only happen when the method follows a naming convention that
+ // implies a related result type, and the original (overridden) method has
+ // a suitable return type, but the new (overriding) method does not have
+ // a suitable return type.
+ QualType ResultType = NewMethod->getResultType();
+ SourceRange ResultTypeRange;
+ if (const TypeSourceInfo *ResultTypeInfo
+ = NewMethod->getResultTypeSourceInfo())
+ ResultTypeRange = ResultTypeInfo->getTypeLoc().getSourceRange();
+
+ // Figure out which class this method is part of, if any.
+ ObjCInterfaceDecl *CurrentClass
+ = dyn_cast<ObjCInterfaceDecl>(NewMethod->getDeclContext());
+ if (!CurrentClass) {
+ DeclContext *DC = NewMethod->getDeclContext();
+ if (ObjCCategoryDecl *Cat = dyn_cast<ObjCCategoryDecl>(DC))
+ CurrentClass = Cat->getClassInterface();
+ else if (ObjCImplDecl *Impl = dyn_cast<ObjCImplDecl>(DC))
+ CurrentClass = Impl->getClassInterface();
+ else if (ObjCCategoryImplDecl *CatImpl
+ = dyn_cast<ObjCCategoryImplDecl>(DC))
+ CurrentClass = CatImpl->getClassInterface();
+ }
+
+ if (CurrentClass) {
+ Diag(NewMethod->getLocation(),
+ diag::warn_related_result_type_compatibility_class)
+ << Context.getObjCInterfaceType(CurrentClass)
+ << ResultType
+ << ResultTypeRange;
+ } else {
+ Diag(NewMethod->getLocation(),
+ diag::warn_related_result_type_compatibility_protocol)
+ << ResultType
+ << ResultTypeRange;
+ }
+
+ Diag(Overridden->getLocation(), diag::note_related_result_type_overridden)
+ << Overridden->getMethodFamily();
+ }
+
+ return false;
+}
+
+
+static bool CheckObjCMethodOverrides(Sema &S, ObjCMethodDecl *NewMethod,
+ DeclContext *DC,
+ bool SkipCurrent = true) {
+ if (!DC)
+ return false;
+
+ if (!SkipCurrent) {
+ // Look for this method. If we find it, we're done.
+ Selector Sel = NewMethod->getSelector();
+ bool IsInstance = NewMethod->isInstanceMethod();
+ DeclContext::lookup_const_iterator Meth, MethEnd;
+ for (llvm::tie(Meth, MethEnd) = DC->lookup(Sel); Meth != MethEnd; ++Meth) {
+ ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(*Meth);
+ if (MD && MD->isInstanceMethod() == IsInstance)
+ return S.CheckObjCMethodOverride(NewMethod, MD, false);
+ }
+ }
+
+ if (ObjCInterfaceDecl *Class = llvm::dyn_cast<ObjCInterfaceDecl>(DC)) {
+ // Look through categories.
+ for (ObjCCategoryDecl *Category = Class->getCategoryList();
+ Category; Category = Category->getNextClassCategory()) {
+ if (CheckObjCMethodOverrides(S, NewMethod, Category, false))
+ return true;
+ }
+
+ // Look through protocols.
+ for (ObjCList<ObjCProtocolDecl>::iterator I = Class->protocol_begin(),
+ IEnd = Class->protocol_end();
+ I != IEnd; ++I)
+ if (CheckObjCMethodOverrides(S, NewMethod, *I, false))
+ return true;
+
+ // Look in our superclass.
+ return CheckObjCMethodOverrides(S, NewMethod, Class->getSuperClass(),
+ false);
+ }
+
+ if (ObjCCategoryDecl *Category = dyn_cast<ObjCCategoryDecl>(DC)) {
+ // Look through protocols.
+ for (ObjCList<ObjCProtocolDecl>::iterator I = Category->protocol_begin(),
+ IEnd = Category->protocol_end();
+ I != IEnd; ++I)
+ if (CheckObjCMethodOverrides(S, NewMethod, *I, false))
+ return true;
+
+ return false;
+ }
+
+ if (ObjCProtocolDecl *Protocol = dyn_cast<ObjCProtocolDecl>(DC)) {
+ // Look through protocols.
+ for (ObjCList<ObjCProtocolDecl>::iterator I = Protocol->protocol_begin(),
+ IEnd = Protocol->protocol_end();
+ I != IEnd; ++I)
+ if (CheckObjCMethodOverrides(S, NewMethod, *I, false))
+ return true;
+
+ return false;
+ }
+
+ return false;
+}
+
+bool Sema::CheckObjCMethodOverrides(ObjCMethodDecl *NewMethod,
+ DeclContext *DC) {
+ if (ObjCInterfaceDecl *Class = dyn_cast<ObjCInterfaceDecl>(DC))
+ return ::CheckObjCMethodOverrides(*this, NewMethod, Class);
+
+ if (ObjCCategoryDecl *Category = dyn_cast<ObjCCategoryDecl>(DC))
+ return ::CheckObjCMethodOverrides(*this, NewMethod, Category);
+
+ if (ObjCProtocolDecl *Protocol = dyn_cast<ObjCProtocolDecl>(DC))
+ return ::CheckObjCMethodOverrides(*this, NewMethod, Protocol);
+
+ if (ObjCImplementationDecl *Impl = dyn_cast<ObjCImplementationDecl>(DC))
+ return ::CheckObjCMethodOverrides(*this, NewMethod,
+ Impl->getClassInterface());
+
+ if (ObjCCategoryImplDecl *CatImpl = dyn_cast<ObjCCategoryImplDecl>(DC))
+ return ::CheckObjCMethodOverrides(*this, NewMethod,
+ CatImpl->getClassInterface());
+
+ return ::CheckObjCMethodOverrides(*this, NewMethod, CurContext);
+}
+
static void DiagnoseObjCImplementedDeprecations(Sema &S,
NamedDecl *ND,
SourceLocation ImplLoc,
@@ -272,23 +407,27 @@ Decl *Sema::ActOnCompatiblityAlias(SourceLocation AtLoc,
return AliasDecl;
}
-void Sema::CheckForwardProtocolDeclarationForCircularDependency(
+bool Sema::CheckForwardProtocolDeclarationForCircularDependency(
IdentifierInfo *PName,
SourceLocation &Ploc, SourceLocation PrevLoc,
const ObjCList<ObjCProtocolDecl> &PList) {
+
+ bool res = false;
for (ObjCList<ObjCProtocolDecl>::iterator I = PList.begin(),
E = PList.end(); I != E; ++I) {
-
if (ObjCProtocolDecl *PDecl = LookupProtocol((*I)->getIdentifier(),
Ploc)) {
if (PDecl->getIdentifier() == PName) {
Diag(Ploc, diag::err_protocol_has_circular_dependency);
Diag(PrevLoc, diag::note_previous_definition);
+ res = true;
}
- CheckForwardProtocolDeclarationForCircularDependency(PName, Ploc,
- PDecl->getLocation(), PDecl->getReferencedProtocols());
+ if (CheckForwardProtocolDeclarationForCircularDependency(PName, Ploc,
+ PDecl->getLocation(), PDecl->getReferencedProtocols()))
+ res = true;
}
}
+ return res;
}
Decl *
@@ -300,6 +439,7 @@ Sema::ActOnStartProtocolInterface(SourceLocation AtProtoInterfaceLoc,
const SourceLocation *ProtoLocs,
SourceLocation EndProtoLoc,
AttributeList *AttrList) {
+ bool err = false;
// FIXME: Deal with AttrList.
assert(ProtocolName && "Missing protocol identifier");
ObjCProtocolDecl *PDecl = LookupProtocol(ProtocolName, ProtocolLoc);
@@ -314,8 +454,8 @@ Sema::ActOnStartProtocolInterface(SourceLocation AtProtoInterfaceLoc,
}
ObjCList<ObjCProtocolDecl> PList;
PList.set((ObjCProtocolDecl *const*)ProtoRefs, NumProtoRefs, Context);
- CheckForwardProtocolDeclarationForCircularDependency(
- ProtocolName, ProtocolLoc, PDecl->getLocation(), PList);
+ err = CheckForwardProtocolDeclarationForCircularDependency(
+ ProtocolName, ProtocolLoc, PDecl->getLocation(), PList);
// Make sure the cached decl gets a valid start location.
PDecl->setLocation(AtProtoInterfaceLoc);
@@ -331,7 +471,7 @@ Sema::ActOnStartProtocolInterface(SourceLocation AtProtoInterfaceLoc,
}
if (AttrList)
ProcessDeclAttributeList(TUScope, PDecl, AttrList);
- if (NumProtoRefs) {
+ if (!err && NumProtoRefs ) {
/// Check then save referenced protocols.
PDecl->setProtocolList((ObjCProtocolDecl**)ProtoRefs, NumProtoRefs,
ProtoLocs, Context);
@@ -1712,11 +1852,71 @@ bool containsInvalidMethodImplAttribute(const AttrVec &A) {
return false;
}
+/// \brief Check whether the declared result type of the given Objective-C
+/// method declaration is compatible with the method's class.
+///
+static bool
+CheckRelatedResultTypeCompatibility(Sema &S, ObjCMethodDecl *Method,
+ ObjCInterfaceDecl *CurrentClass) {
+ QualType ResultType = Method->getResultType();
+ SourceRange ResultTypeRange;
+ if (const TypeSourceInfo *ResultTypeInfo = Method->getResultTypeSourceInfo())
+ ResultTypeRange = ResultTypeInfo->getTypeLoc().getSourceRange();
+
+ // If an Objective-C method inherits its related result type, then its
+ // declared result type must be compatible with its own class type. The
+ // declared result type is compatible if:
+ if (const ObjCObjectPointerType *ResultObjectType
+ = ResultType->getAs<ObjCObjectPointerType>()) {
+ // - it is id or qualified id, or
+ if (ResultObjectType->isObjCIdType() ||
+ ResultObjectType->isObjCQualifiedIdType())
+ return false;
+
+ if (CurrentClass) {
+ if (ObjCInterfaceDecl *ResultClass
+ = ResultObjectType->getInterfaceDecl()) {
+ // - it is the same as the method's class type, or
+ if (CurrentClass == ResultClass)
+ return false;
+
+ // - it is a superclass of the method's class type
+ if (ResultClass->isSuperClassOf(CurrentClass))
+ return false;
+ }
+ }
+ }
+
+ return true;
+}
+
+/// \brief Determine if any method in the global method pool has an inferred
+/// result type.
+static bool
+anyMethodInfersRelatedResultType(Sema &S, Selector Sel, bool IsInstance) {
+ Sema::GlobalMethodPool::iterator Pos = S.MethodPool.find(Sel);
+ if (Pos == S.MethodPool.end()) {
+ if (S.ExternalSource)
+ Pos = S.ReadMethodPool(Sel);
+ else
+ return 0;
+ }
+
+ ObjCMethodList &List = IsInstance ? Pos->second.first : Pos->second.second;
+ for (ObjCMethodList *M = &List; M; M = M->Next) {
+ if (M->Method && M->Method->hasRelatedResultType())
+ return true;
+ }
+
+ return false;
+}
+
Decl *Sema::ActOnMethodDeclaration(
Scope *S,
SourceLocation MethodLoc, SourceLocation EndLoc,
tok::TokenKind MethodType, Decl *ClassDecl,
ObjCDeclSpec &ReturnQT, ParsedType ReturnType,
+ SourceLocation SelectorStartLoc,
Selector Sel,
// optional arguments. The number of types/arguments is obtained
// from the Sel.getNumArgs().
@@ -1741,7 +1941,7 @@ Decl *Sema::ActOnMethodDeclaration(
Diag(MethodLoc, diag::err_object_cannot_be_passed_returned_by_value)
<< 0 << resultDeclType;
return 0;
- }
+ }
} else // get the type for "id".
resultDeclType = Context.getObjCIdType();
@@ -1751,9 +1951,10 @@ Decl *Sema::ActOnMethodDeclaration(
cast<DeclContext>(ClassDecl),
MethodType == tok::minus, isVariadic,
false, false,
- MethodDeclKind == tok::objc_optional ?
- ObjCMethodDecl::Optional :
- ObjCMethodDecl::Required);
+ MethodDeclKind == tok::objc_optional
+ ? ObjCMethodDecl::Optional
+ : ObjCMethodDecl::Required,
+ false);
llvm::SmallVector<ParmVarDecl*, 16> Params;
@@ -1849,6 +2050,7 @@ Decl *Sema::ActOnMethodDeclaration(
}
InterfaceMD = ImpDecl->getClassInterface()->getMethod(Sel,
MethodType == tok::minus);
+
if (ObjCMethod->hasAttrs() &&
containsInvalidMethodImplAttribute(ObjCMethod->getAttrs()))
Diag(EndLoc, diag::warn_attribute_method_def);
@@ -1861,6 +2063,10 @@ Decl *Sema::ActOnMethodDeclaration(
PrevMethod = CatImpDecl->getClassMethod(Sel);
CatImpDecl->addClassMethod(ObjCMethod);
}
+
+ if (ObjCCategoryDecl *Cat = CatImpDecl->getCategoryDecl())
+ InterfaceMD = Cat->getMethod(Sel, MethodType == tok::minus);
+
if (ObjCMethod->hasAttrs() &&
containsInvalidMethodImplAttribute(ObjCMethod->getAttrs()))
Diag(EndLoc, diag::warn_attribute_method_def);
@@ -1874,10 +2080,65 @@ Decl *Sema::ActOnMethodDeclaration(
Diag(PrevMethod->getLocation(), diag::note_previous_declaration);
}
+ // If this Objective-C method does not have a related result type, but we
+ // are allowed to infer related result types, try to do so based on the
+ // method family.
+ ObjCInterfaceDecl *CurrentClass = dyn_cast<ObjCInterfaceDecl>(ClassDecl);
+ if (!CurrentClass) {
+ if (ObjCCategoryDecl *Cat = dyn_cast<ObjCCategoryDecl>(ClassDecl))
+ CurrentClass = Cat->getClassInterface();
+ else if (ObjCImplDecl *Impl = dyn_cast<ObjCImplDecl>(ClassDecl))
+ CurrentClass = Impl->getClassInterface();
+ else if (ObjCCategoryImplDecl *CatImpl
+ = dyn_cast<ObjCCategoryImplDecl>(ClassDecl))
+ CurrentClass = CatImpl->getClassInterface();
+ }
+
// Merge information down from the interface declaration if we have one.
- if (InterfaceMD)
+ if (InterfaceMD) {
+ // Inherit the related result type, if we can.
+ if (InterfaceMD->hasRelatedResultType() &&
+ !CheckRelatedResultTypeCompatibility(*this, ObjCMethod, CurrentClass))
+ ObjCMethod->SetRelatedResultType();
+
mergeObjCMethodDecls(ObjCMethod, InterfaceMD);
-
+ }
+
+ if (!ObjCMethod->hasRelatedResultType() &&
+ getLangOptions().ObjCInferRelatedResultType) {
+ bool InferRelatedResultType = false;
+ switch (ObjCMethod->getMethodFamily()) {
+ case OMF_None:
+ case OMF_copy:
+ case OMF_dealloc:
+ case OMF_mutableCopy:
+ case OMF_release:
+ case OMF_retainCount:
+ break;
+
+ case OMF_alloc:
+ case OMF_new:
+ InferRelatedResultType = ObjCMethod->isClassMethod();
+ break;
+
+ case OMF_init:
+ case OMF_autorelease:
+ case OMF_retain:
+ case OMF_self:
+ InferRelatedResultType = ObjCMethod->isInstanceMethod();
+ break;
+ }
+
+ if (InferRelatedResultType &&
+ !CheckRelatedResultTypeCompatibility(*this, ObjCMethod, CurrentClass))
+ ObjCMethod->SetRelatedResultType();
+
+ if (!InterfaceMD &&
+ anyMethodInfersRelatedResultType(*this, ObjCMethod->getSelector(),
+ ObjCMethod->isInstanceMethod()))
+ CheckObjCMethodOverrides(ObjCMethod, cast<DeclContext>(ClassDecl));
+ }
+
return ObjCMethod;
}
diff --git a/lib/Sema/SemaExceptionSpec.cpp b/lib/Sema/SemaExceptionSpec.cpp
index f1033dc..7bcec31 100644
--- a/lib/Sema/SemaExceptionSpec.cpp
+++ b/lib/Sema/SemaExceptionSpec.cpp
@@ -298,8 +298,6 @@ bool Sema::CheckEquivalentExceptionSpec(const PartialDiagnostic &DiagID,
// - both are non-throwing, regardless of their form,
// - both have the form noexcept(constant-expression) and the constant-
// expressions are equivalent,
- // - one exception-specification is a noexcept-specification allowing all
- // exceptions and the other is of the form throw(type-id-list), or
// - both are dynamic-exception-specifications that have the same set of
// adjusted types.
//
@@ -307,8 +305,6 @@ bool Sema::CheckEquivalentExceptionSpec(const PartialDiagnostic &DiagID,
// of the form throw(), noexcept, or noexcept(constant-expression) where the
// constant-expression yields true.
//
- // CWG 1073 Proposed resolution: Strike the third bullet above.
- //
// C++0x [except.spec]p4: If any declaration of a function has an exception-
// specifier that is not a noexcept-specification allowing all exceptions,
// all declarations [...] of that function shall have a compatible
@@ -320,6 +316,9 @@ bool Sema::CheckEquivalentExceptionSpec(const PartialDiagnostic &DiagID,
ExceptionSpecificationType OldEST = Old->getExceptionSpecType();
ExceptionSpecificationType NewEST = New->getExceptionSpecType();
+ assert(OldEST != EST_Delayed && NewEST != EST_Delayed &&
+ "Shouldn't see unknown exception specifications here");
+
// Shortcut the case where both have no spec.
if (OldEST == EST_None && NewEST == EST_None)
return false;
@@ -506,6 +505,9 @@ bool Sema::CheckExceptionSpecSubset(
ExceptionSpecificationType SubEST = Subset->getExceptionSpecType();
+ assert(SuperEST != EST_Delayed && SubEST != EST_Delayed &&
+ "Shouldn't see unknown exception specifications here");
+
// It does not. If the subset contains everything, we've failed.
if (SubEST == EST_None || SubEST == EST_MSAny) {
Diag(SubLoc, DiagID);
@@ -701,7 +703,23 @@ bool Sema::CheckExceptionSpecCompatibility(Expr *From, QualType ToType)
bool Sema::CheckOverridingFunctionExceptionSpec(const CXXMethodDecl *New,
const CXXMethodDecl *Old) {
- return CheckExceptionSpecSubset(PDiag(diag::err_override_exception_spec),
+ if (getLangOptions().CPlusPlus0x && isa<CXXDestructorDecl>(New)) {
+ // Don't check uninstantiated template destructors at all. We can only
+ // synthesize correct specs after the template is instantiated.
+ if (New->getParent()->isDependentType())
+ return false;
+ if (New->getParent()->isBeingDefined()) {
+ // The destructor might be updated once the definition is finished. So
+ // remember it and check later.
+ DelayedDestructorExceptionSpecChecks.push_back(std::make_pair(
+ cast<CXXDestructorDecl>(New), cast<CXXDestructorDecl>(Old)));
+ return false;
+ }
+ }
+ unsigned DiagID = diag::err_override_exception_spec;
+ if (getLangOptions().Microsoft)
+ DiagID = diag::warn_override_exception_spec;
+ return CheckExceptionSpecSubset(PDiag(DiagID),
PDiag(diag::note_overridden_virtual_function),
Old->getType()->getAs<FunctionProtoType>(),
Old->getLocation(),
diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp
index 20b92b8..0549e94 100644
--- a/lib/Sema/SemaExpr.cpp
+++ b/lib/Sema/SemaExpr.cpp
@@ -449,18 +449,58 @@ ExprResult Sema::DefaultVariadicArgumentPromotion(Expr *E, VariadicCallType CT,
if (FDecl && FDecl->getBuiltinID() == Builtin::BI__builtin_va_start)
return Owned(E);
+ // Don't allow one to pass an Objective-C interface to a vararg.
if (E->getType()->isObjCObjectType() &&
- DiagRuntimeBehavior(E->getLocStart(), 0,
- PDiag(diag::err_cannot_pass_objc_interface_to_vararg)
- << E->getType() << CT))
+ DiagRuntimeBehavior(E->getLocStart(), 0,
+ PDiag(diag::err_cannot_pass_objc_interface_to_vararg)
+ << E->getType() << CT))
return ExprError();
-
- if (!E->getType()->isPODType() &&
- DiagRuntimeBehavior(E->getLocStart(), 0,
+
+ if (!E->getType()->isPODType()) {
+ // C++0x [expr.call]p7:
+ // Passing a potentially-evaluated argument of class type (Clause 9)
+ // having a non-trivial copy constructor, a non-trivial move constructor,
+ // or a non-trivial destructor, with no corresponding parameter,
+ // is conditionally-supported with implementation-defined semantics.
+ bool TrivialEnough = false;
+ if (getLangOptions().CPlusPlus0x && !E->getType()->isDependentType()) {
+ if (CXXRecordDecl *Record = E->getType()->getAsCXXRecordDecl()) {
+ if (Record->hasTrivialCopyConstructor() &&
+ Record->hasTrivialMoveConstructor() &&
+ Record->hasTrivialDestructor())
+ TrivialEnough = true;
+ }
+ }
+
+ if (TrivialEnough) {
+ // Nothing to diagnose. This is okay.
+ } else if (DiagRuntimeBehavior(E->getLocStart(), 0,
PDiag(diag::warn_cannot_pass_non_pod_arg_to_vararg)
- << E->getType() << CT))
- return ExprError();
+ << getLangOptions().CPlusPlus0x << E->getType()
+ << CT)) {
+ // Turn this into a trap.
+ CXXScopeSpec SS;
+ UnqualifiedId Name;
+ Name.setIdentifier(PP.getIdentifierInfo("__builtin_trap"),
+ E->getLocStart());
+ ExprResult TrapFn = ActOnIdExpression(TUScope, SS, Name, true, false);
+ if (TrapFn.isInvalid())
+ return ExprError();
+ ExprResult Call = ActOnCallExpr(TUScope, TrapFn.get(), E->getLocStart(),
+ MultiExprArg(), E->getLocEnd());
+ if (Call.isInvalid())
+ return ExprError();
+
+ ExprResult Comma = ActOnBinOp(TUScope, E->getLocStart(), tok::comma,
+ Call.get(), E);
+ if (Comma.isInvalid())
+ return ExprError();
+
+ E = Comma.get();
+ }
+ }
+
return Owned(E);
}
@@ -1293,8 +1333,8 @@ Sema::BuildAnonymousStructUnionMemberReference(const CXXScopeSpec &SS,
// 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".
- CXXMethodDecl *method = tryCaptureCXXThis();
- if (!method) {
+ QualType ThisTy = getAndCaptureCurrentThisType();
+ if (ThisTy.isNull()) {
Diag(loc, diag::err_invalid_member_use_in_static_method)
<< indirectField->getDeclName();
return ExprError();
@@ -1302,10 +1342,9 @@ Sema::BuildAnonymousStructUnionMemberReference(const CXXScopeSpec &SS,
// Our base object expression is "this".
baseObjectExpr =
- new (Context) CXXThisExpr(loc, method->getThisType(Context),
- /*isImplicit=*/ true);
+ new (Context) CXXThisExpr(loc, ThisTy, /*isImplicit=*/ true);
baseObjectIsPointer = true;
- baseQuals = Qualifiers::fromCVRMask(method->getTypeQualifiers());
+ baseQuals = ThisTy->castAs<PointerType>()->getPointeeType().getQualifiers();
}
// Build the implicit member references to the field of the
@@ -1452,14 +1491,23 @@ enum IMAKind {
/// conservatively answer "yes", in which case some errors will simply
/// not be caught until template-instantiation.
static IMAKind ClassifyImplicitMemberAccess(Sema &SemaRef,
+ Scope *CurScope,
const LookupResult &R) {
assert(!R.empty() && (*R.begin())->isCXXClassMember());
DeclContext *DC = SemaRef.getFunctionLevelDeclContext();
+
bool isStaticContext =
(!isa<CXXMethodDecl>(DC) ||
cast<CXXMethodDecl>(DC)->isStatic());
+ // C++0x [expr.prim]p4:
+ // Otherwise, if a member-declarator declares a non-static data member
+ // of a class X, the expression this is a prvalue of type "pointer to X"
+ // within the optional brace-or-equal-initializer.
+ if (CurScope->getFlags() & Scope::ThisScope)
+ isStaticContext = false;
+
if (R.isUnresolvableResult())
return isStaticContext ? IMA_Unresolved_StaticContext : IMA_Unresolved;
@@ -1507,8 +1555,11 @@ static IMAKind ClassifyImplicitMemberAccess(Sema &SemaRef,
return IMA_Error_StaticContext;
}
- CXXRecordDecl *
- contextClass = cast<CXXMethodDecl>(DC)->getParent()->getCanonicalDecl();
+ CXXRecordDecl *contextClass;
+ if (CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(DC))
+ contextClass = MD->getParent()->getCanonicalDecl();
+ else
+ contextClass = cast<CXXRecordDecl>(DC);
// [class.mfct.non-static]p3:
// ...is used in the body of a non-static member function of class X,
@@ -1986,7 +2037,7 @@ ExprResult
Sema::BuildPossibleImplicitMemberExpr(const CXXScopeSpec &SS,
LookupResult &R,
const TemplateArgumentListInfo *TemplateArgs) {
- switch (ClassifyImplicitMemberAccess(*this, R)) {
+ switch (ClassifyImplicitMemberAccess(*this, CurScope, R)) {
case IMA_Instance:
return BuildImplicitMemberExpr(SS, R, TemplateArgs, true);
@@ -2429,19 +2480,18 @@ Sema::BuildImplicitMemberExpr(const CXXScopeSpec &SS,
// If this is known to be an instance access, go ahead and build an
// implicit 'this' expression now.
// 'this' expression now.
- CXXMethodDecl *method = tryCaptureCXXThis();
- assert(method && "didn't correctly pre-flight capture of 'this'");
+ QualType ThisTy = getAndCaptureCurrentThisType();
+ assert(!ThisTy.isNull() && "didn't correctly pre-flight capture of 'this'");
- QualType thisType = method->getThisType(Context);
Expr *baseExpr = 0; // null signifies implicit access
if (IsKnownInstance) {
SourceLocation Loc = R.getNameLoc();
if (SS.getRange().isValid())
Loc = SS.getRange().getBegin();
- baseExpr = new (Context) CXXThisExpr(loc, thisType, /*isImplicit=*/true);
+ baseExpr = new (Context) CXXThisExpr(loc, ThisTy, /*isImplicit=*/true);
}
- return BuildMemberReferenceExpr(baseExpr, thisType,
+ return BuildMemberReferenceExpr(baseExpr, ThisTy,
/*OpLoc*/ SourceLocation(),
/*IsArrow*/ true,
SS,
@@ -3014,8 +3064,120 @@ ExprResult Sema::ActOnParenExpr(SourceLocation L,
return Owned(new (Context) ParenExpr(L, R, E));
}
+static bool CheckVecStepTraitOperandType(Sema &S, QualType T,
+ SourceLocation Loc,
+ SourceRange ArgRange) {
+ // [OpenCL 1.1 6.11.12] "The vec_step built-in function takes a built-in
+ // scalar or vector data type argument..."
+ // Every built-in scalar type (OpenCL 1.1 6.1.1) is either an arithmetic
+ // type (C99 6.2.5p18) or void.
+ if (!(T->isArithmeticType() || T->isVoidType() || T->isVectorType())) {
+ S.Diag(Loc, diag::err_vecstep_non_scalar_vector_type)
+ << T << ArgRange;
+ return true;
+ }
+
+ assert((T->isVoidType() || !T->isIncompleteType()) &&
+ "Scalar types should always be complete");
+ return false;
+}
+
+static bool CheckExtensionTraitOperandType(Sema &S, QualType T,
+ SourceLocation Loc,
+ SourceRange ArgRange,
+ UnaryExprOrTypeTrait TraitKind) {
+ // C99 6.5.3.4p1:
+ if (T->isFunctionType()) {
+ // alignof(function) is allowed as an extension.
+ if (TraitKind == UETT_SizeOf)
+ S.Diag(Loc, diag::ext_sizeof_function_type) << ArgRange;
+ return false;
+ }
+
+ // Allow sizeof(void)/alignof(void) as an extension.
+ if (T->isVoidType()) {
+ S.Diag(Loc, diag::ext_sizeof_void_type) << TraitKind << ArgRange;
+ return false;
+ }
+
+ return true;
+}
+
+static bool CheckObjCTraitOperandConstraints(Sema &S, QualType T,
+ SourceLocation Loc,
+ SourceRange ArgRange,
+ UnaryExprOrTypeTrait TraitKind) {
+ // Reject sizeof(interface) and sizeof(interface<proto>) in 64-bit mode.
+ if (S.LangOpts.ObjCNonFragileABI && T->isObjCObjectType()) {
+ S.Diag(Loc, diag::err_sizeof_nonfragile_interface)
+ << T << (TraitKind == UETT_SizeOf)
+ << ArgRange;
+ return true;
+ }
+
+ return false;
+}
+
+/// \brief Check the constrains on expression operands to unary type expression
+/// and type traits.
+///
+/// Completes any types necessary and validates the constraints on the operand
+/// expression. The logic mostly mirrors the type-based overload, but may modify
+/// the expression as it completes the type for that expression through template
+/// instantiation, etc.
+bool Sema::CheckUnaryExprOrTypeTraitOperand(Expr *Op,
+ UnaryExprOrTypeTrait ExprKind) {
+ QualType ExprTy = Op->getType();
+
+ // C++ [expr.sizeof]p2: "When applied to a reference or a reference type,
+ // the result is the size of the referenced type."
+ // C++ [expr.alignof]p3: "When alignof is applied to a reference type, the
+ // result shall be the alignment of the referenced type."
+ if (const ReferenceType *Ref = ExprTy->getAs<ReferenceType>())
+ ExprTy = Ref->getPointeeType();
+
+ if (ExprKind == UETT_VecStep)
+ return CheckVecStepTraitOperandType(*this, ExprTy, Op->getExprLoc(),
+ Op->getSourceRange());
+
+ // Whitelist some types as extensions
+ if (!CheckExtensionTraitOperandType(*this, ExprTy, Op->getExprLoc(),
+ Op->getSourceRange(), ExprKind))
+ return false;
+
+ if (RequireCompleteExprType(Op,
+ PDiag(diag::err_sizeof_alignof_incomplete_type)
+ << ExprKind << Op->getSourceRange(),
+ std::make_pair(SourceLocation(), PDiag(0))))
+ return true;
+
+ // Completeing the expression's type may have changed it.
+ ExprTy = Op->getType();
+ if (const ReferenceType *Ref = ExprTy->getAs<ReferenceType>())
+ ExprTy = Ref->getPointeeType();
+
+ if (CheckObjCTraitOperandConstraints(*this, ExprTy, Op->getExprLoc(),
+ Op->getSourceRange(), ExprKind))
+ return true;
+
+ return false;
+}
+
+/// \brief Check the constraints on operands to unary expression and type
+/// traits.
+///
+/// This will complete any types necessary, and validate the various constraints
+/// on those operands.
+///
/// The UsualUnaryConversions() function is *not* called by this routine.
-/// See C99 6.3.2.1p[2-4] for more details.
+/// C99 6.3.2.1p[2-4] all state:
+/// Except when it is the operand of the sizeof operator ...
+///
+/// C++ [expr.sizeof]p4
+/// The lvalue-to-rvalue, array-to-pointer, and function-to-pointer
+/// standard conversions are not applied to the operand of sizeof.
+///
+/// This policy is followed for all of the unary trait expressions.
bool Sema::CheckUnaryExprOrTypeTraitOperand(QualType exprType,
SourceLocation OpLoc,
SourceRange ExprRange,
@@ -3030,55 +3192,27 @@ bool Sema::CheckUnaryExprOrTypeTraitOperand(QualType exprType,
if (const ReferenceType *Ref = exprType->getAs<ReferenceType>())
exprType = Ref->getPointeeType();
- // [OpenCL 1.1 6.11.12] "The vec_step built-in function takes a built-in
- // scalar or vector data type argument..."
- // Every built-in scalar type (OpenCL 1.1 6.1.1) is either an arithmetic
- // type (C99 6.2.5p18) or void.
- if (ExprKind == UETT_VecStep) {
- if (!(exprType->isArithmeticType() || exprType->isVoidType() ||
- exprType->isVectorType())) {
- Diag(OpLoc, diag::err_vecstep_non_scalar_vector_type)
- << exprType << ExprRange;
- return true;
- }
- }
+ if (ExprKind == UETT_VecStep)
+ return CheckVecStepTraitOperandType(*this, exprType, OpLoc, ExprRange);
- // C99 6.5.3.4p1:
- if (exprType->isFunctionType()) {
- // alignof(function) is allowed as an extension.
- if (ExprKind == UETT_SizeOf)
- Diag(OpLoc, diag::ext_sizeof_function_type)
- << ExprRange;
+ // Whitelist some types as extensions
+ if (!CheckExtensionTraitOperandType(*this, exprType, OpLoc, ExprRange,
+ ExprKind))
return false;
- }
-
- // Allow sizeof(void)/alignof(void) as an extension. vec_step(void) is not
- // an extension, as void is a built-in scalar type (OpenCL 1.1 6.1.1).
- if (exprType->isVoidType()) {
- if (ExprKind != UETT_VecStep)
- Diag(OpLoc, diag::ext_sizeof_void_type)
- << ExprKind << ExprRange;
- return false;
- }
if (RequireCompleteType(OpLoc, exprType,
PDiag(diag::err_sizeof_alignof_incomplete_type)
<< ExprKind << ExprRange))
return true;
- // Reject sizeof(interface) and sizeof(interface<proto>) in 64-bit mode.
- if (LangOpts.ObjCNonFragileABI && exprType->isObjCObjectType()) {
- Diag(OpLoc, diag::err_sizeof_nonfragile_interface)
- << exprType << (ExprKind == UETT_SizeOf)
- << ExprRange;
+ if (CheckObjCTraitOperandConstraints(*this, exprType, OpLoc, ExprRange,
+ ExprKind))
return true;
- }
return false;
}
-static bool CheckAlignOfExpr(Sema &S, Expr *E, SourceLocation OpLoc,
- SourceRange ExprRange) {
+static bool CheckAlignOfExpr(Sema &S, Expr *E) {
E = E->IgnoreParens();
// alignof decl is always ok.
@@ -3090,7 +3224,8 @@ static bool CheckAlignOfExpr(Sema &S, Expr *E, SourceLocation OpLoc,
return false;
if (E->getBitField()) {
- S. Diag(OpLoc, diag::err_sizeof_alignof_bitfield) << 1 << ExprRange;
+ S.Diag(E->getExprLoc(), diag::err_sizeof_alignof_bitfield)
+ << 1 << E->getSourceRange();
return true;
}
@@ -3100,20 +3235,17 @@ static bool CheckAlignOfExpr(Sema &S, Expr *E, SourceLocation OpLoc,
if (isa<FieldDecl>(ME->getMemberDecl()))
return false;
- return S.CheckUnaryExprOrTypeTraitOperand(E->getType(), OpLoc, ExprRange,
- UETT_AlignOf);
+ return S.CheckUnaryExprOrTypeTraitOperand(E, UETT_AlignOf);
}
-bool Sema::CheckVecStepExpr(Expr *E, SourceLocation OpLoc,
- SourceRange ExprRange) {
+bool Sema::CheckVecStepExpr(Expr *E) {
E = E->IgnoreParens();
// Cannot know anything else if the expression is dependent.
if (E->isTypeDependent())
return false;
- return CheckUnaryExprOrTypeTraitOperand(E->getType(), OpLoc, ExprRange,
- UETT_VecStep);
+ return CheckUnaryExprOrTypeTraitOperand(E, UETT_VecStep);
}
/// \brief Build a sizeof or alignof expression given a type operand.
@@ -3141,35 +3273,33 @@ Sema::CreateUnaryExprOrTypeTraitExpr(TypeSourceInfo *TInfo,
/// operand.
ExprResult
Sema::CreateUnaryExprOrTypeTraitExpr(Expr *E, SourceLocation OpLoc,
- UnaryExprOrTypeTrait ExprKind,
- SourceRange R) {
+ UnaryExprOrTypeTrait ExprKind) {
// Verify that the operand is valid.
bool isInvalid = false;
if (E->isTypeDependent()) {
// Delay type-checking for type-dependent expressions.
} else if (ExprKind == UETT_AlignOf) {
- isInvalid = CheckAlignOfExpr(*this, E, OpLoc, R);
+ isInvalid = CheckAlignOfExpr(*this, E);
} else if (ExprKind == UETT_VecStep) {
- isInvalid = CheckVecStepExpr(E, OpLoc, R);
+ isInvalid = CheckVecStepExpr(E);
} else if (E->getBitField()) { // C99 6.5.3.4p1.
- Diag(OpLoc, diag::err_sizeof_alignof_bitfield) << 0;
+ Diag(E->getExprLoc(), diag::err_sizeof_alignof_bitfield) << 0;
isInvalid = true;
} else if (E->getType()->isPlaceholderType()) {
ExprResult PE = CheckPlaceholderExpr(E);
if (PE.isInvalid()) return ExprError();
- return CreateUnaryExprOrTypeTraitExpr(PE.take(), OpLoc, ExprKind, R);
+ return CreateUnaryExprOrTypeTraitExpr(PE.take(), OpLoc, ExprKind);
} else {
- isInvalid = CheckUnaryExprOrTypeTraitOperand(E->getType(), OpLoc, R,
- UETT_SizeOf);
+ isInvalid = CheckUnaryExprOrTypeTraitOperand(E, UETT_SizeOf);
}
if (isInvalid)
return ExprError();
// C99 6.5.3.4p4: the type (an unsigned integer type) is size_t.
- return Owned(new (Context) UnaryExprOrTypeTraitExpr(ExprKind, E,
- Context.getSizeType(),
- OpLoc, R.getEnd()));
+ return Owned(new (Context) UnaryExprOrTypeTraitExpr(
+ ExprKind, E, Context.getSizeType(), OpLoc,
+ E->getSourceRange().getEnd()));
}
/// ActOnUnaryExprOrTypeTraitExpr - Handle @c sizeof(type) and @c sizeof @c
@@ -3189,10 +3319,7 @@ Sema::ActOnUnaryExprOrTypeTraitExpr(SourceLocation OpLoc,
}
Expr *ArgEx = (Expr *)TyOrEx;
- ExprResult Result
- = CreateUnaryExprOrTypeTraitExpr(ArgEx, OpLoc, ExprKind,
- ArgEx->getSourceRange());
-
+ ExprResult Result = CreateUnaryExprOrTypeTraitExpr(ArgEx, OpLoc, ExprKind);
return move(Result);
}
@@ -4211,7 +4338,11 @@ Sema::LookupMemberExpr(LookupResult &R, ExprResult &BaseExpr,
if (DiagnoseUseOfDecl(PD, MemberLoc))
return ExprError();
- return Owned(new (Context) ObjCPropertyRefExpr(PD, PD->getType(),
+ QualType T = PD->getType();
+ if (ObjCMethodDecl *Getter = PD->getGetterMethodDecl())
+ T = getMessageSendResultType(BaseType, Getter, false, false);
+
+ return Owned(new (Context) ObjCPropertyRefExpr(PD, T,
VK_LValue,
OK_ObjCProperty,
MemberLoc,
@@ -4229,7 +4360,8 @@ Sema::LookupMemberExpr(LookupResult &R, ExprResult &BaseExpr,
if (Decl *SDecl = FindGetterSetterNameDecl(OPT, /*Property id*/0,
SetterSel, Context))
SMD = dyn_cast<ObjCMethodDecl>(SDecl);
- QualType PType = OMD->getSendResultType();
+ QualType PType = getMessageSendResultType(BaseType, OMD, false,
+ false);
ExprValueKind VK = VK_LValue;
if (!getLangOptions().CPlusPlus &&
@@ -4297,7 +4429,8 @@ Sema::LookupMemberExpr(LookupResult &R, ExprResult &BaseExpr,
ExprValueKind VK = VK_LValue;
if (Getter) {
- PType = Getter->getSendResultType();
+ PType = getMessageSendResultType(QualType(OT, 0), Getter, true,
+ false);
if (!getLangOptions().CPlusPlus &&
IsCForbiddenLValueType(Context, PType))
VK = VK_RValue;
@@ -4377,120 +4510,52 @@ Sema::LookupMemberExpr(LookupResult &R, ExprResult &BaseExpr,
// If the user is trying to apply -> or . to a function name, it's probably
// because they forgot parentheses to call that function.
- bool TryCall = false;
- bool Overloaded = false;
- UnresolvedSet<8> AllOverloads;
- if (const OverloadExpr *Overloads = dyn_cast<OverloadExpr>(BaseExpr.get())) {
- AllOverloads.append(Overloads->decls_begin(), Overloads->decls_end());
- TryCall = true;
- Overloaded = true;
- } else if (DeclRefExpr *DeclRef = dyn_cast<DeclRefExpr>(BaseExpr.get())) {
- if (FunctionDecl* Fun = dyn_cast<FunctionDecl>(DeclRef->getDecl())) {
- AllOverloads.addDecl(Fun);
- TryCall = true;
- }
- }
-
- if (TryCall) {
- // Plunder the overload set for something that would make the member
- // expression valid.
- UnresolvedSet<4> ViableOverloads;
- bool HasViableZeroArgOverload = false;
- for (OverloadExpr::decls_iterator it = AllOverloads.begin(),
- DeclsEnd = AllOverloads.end(); it != DeclsEnd; ++it) {
- // Our overload set may include TemplateDecls, which we'll ignore for the
- // purposes of determining whether we can issue a '()' fixit.
- if (const FunctionDecl *OverloadDecl = dyn_cast<FunctionDecl>(*it)) {
- QualType ResultTy = OverloadDecl->getResultType();
- if ((!IsArrow && ResultTy->isRecordType()) ||
- (IsArrow && ResultTy->isPointerType() &&
- ResultTy->getPointeeType()->isRecordType())) {
- ViableOverloads.addDecl(*it);
- if (OverloadDecl->getMinRequiredArguments() == 0) {
- HasViableZeroArgOverload = true;
- }
- }
- }
- }
-
- if (!HasViableZeroArgOverload || ViableOverloads.size() != 1) {
+ QualType ZeroArgCallTy;
+ UnresolvedSet<4> Overloads;
+ if (isExprCallable(*BaseExpr.get(), ZeroArgCallTy, Overloads)) {
+ if (ZeroArgCallTy.isNull()) {
Diag(BaseExpr.get()->getExprLoc(), diag::err_member_reference_needs_call)
- << (AllOverloads.size() > 1) << 0
- << BaseExpr.get()->getSourceRange();
- int ViableOverloadCount = ViableOverloads.size();
- int I;
- for (I = 0; I < ViableOverloadCount; ++I) {
- // FIXME: Magic number for max shown overloads stolen from
- // OverloadCandidateSet::NoteCandidates.
- if (I >= 4 && Diags.getShowOverloads() == Diagnostic::Ovl_Best) {
- break;
- }
- Diag(ViableOverloads[I].getDecl()->getSourceRange().getBegin(),
- diag::note_member_ref_possible_intended_overload);
- }
- if (I != ViableOverloadCount) {
- Diag(BaseExpr.get()->getExprLoc(), diag::note_ovl_too_many_candidates)
- << int(ViableOverloadCount - I);
+ << (Overloads.size() > 1) << 0 << BaseExpr.get()->getSourceRange();
+ UnresolvedSet<2> PlausibleOverloads;
+ for (OverloadExpr::decls_iterator It = Overloads.begin(),
+ DeclsEnd = Overloads.end(); It != DeclsEnd; ++It) {
+ const FunctionDecl *OverloadDecl = cast<FunctionDecl>(*It);
+ QualType OverloadResultTy = OverloadDecl->getResultType();
+ if ((!IsArrow && OverloadResultTy->isRecordType()) ||
+ (IsArrow && OverloadResultTy->isPointerType() &&
+ OverloadResultTy->getPointeeType()->isRecordType()))
+ PlausibleOverloads.addDecl(It.getDecl());
}
+ NoteOverloads(PlausibleOverloads, BaseExpr.get()->getExprLoc());
return ExprError();
}
- } else {
- // We don't have an expression that's convenient to get a Decl from, but we
- // can at least check if the type is "function of 0 arguments which returns
- // an acceptable type".
- const FunctionType *Fun = NULL;
- if (const PointerType *Ptr = BaseType->getAs<PointerType>()) {
- if ((Fun = Ptr->getPointeeType()->getAs<FunctionType>())) {
- TryCall = true;
- }
- } else if ((Fun = BaseType->getAs<FunctionType>())) {
- TryCall = true;
- } else if (BaseType == Context.BoundMemberTy) {
- // Look for the bound-member type. If it's still overloaded,
- // give up, although we probably should have fallen into the
- // OverloadExpr case above if we actually have an overloaded
- // bound member.
- QualType fnType = Expr::findBoundMemberType(BaseExpr.get());
- if (!fnType.isNull()) {
- TryCall = true;
- Fun = fnType->castAs<FunctionType>();
- }
- }
-
- if (TryCall) {
- if (const FunctionProtoType *FPT = dyn_cast<FunctionProtoType>(Fun)) {
- if (FPT->getNumArgs() == 0) {
- QualType ResultTy = Fun->getResultType();
- TryCall = (!IsArrow && ResultTy->isRecordType()) ||
- (IsArrow && ResultTy->isPointerType() &&
- ResultTy->getPointeeType()->isRecordType());
- }
- }
+ if ((!IsArrow && ZeroArgCallTy->isRecordType()) ||
+ (IsArrow && ZeroArgCallTy->isPointerType() &&
+ ZeroArgCallTy->getPointeeType()->isRecordType())) {
+ // At this point, we know BaseExpr looks like it's potentially callable
+ // with 0 arguments, and that it returns something of a reasonable type,
+ // so we can emit a fixit and carry on pretending that BaseExpr was
+ // actually a CallExpr.
+ SourceLocation ParenInsertionLoc =
+ PP.getLocForEndOfToken(BaseExpr.get()->getLocEnd());
+ Diag(BaseExpr.get()->getExprLoc(), diag::err_member_reference_needs_call)
+ << (Overloads.size() > 1) << 1 << BaseExpr.get()->getSourceRange()
+ << FixItHint::CreateInsertion(ParenInsertionLoc, "()");
+ // FIXME: Try this before emitting the fixit, and suppress diagnostics
+ // while doing so.
+ ExprResult NewBase =
+ ActOnCallExpr(0, BaseExpr.take(), ParenInsertionLoc,
+ MultiExprArg(*this, 0, 0),
+ ParenInsertionLoc.getFileLocWithOffset(1));
+ if (NewBase.isInvalid())
+ return ExprError();
+ BaseExpr = NewBase;
+ BaseExpr = DefaultFunctionArrayConversion(BaseExpr.take());
+ return LookupMemberExpr(R, BaseExpr, IsArrow, OpLoc, SS,
+ ObjCImpDecl, HasTemplateArgs);
}
}
- if (TryCall) {
- // At this point, we know BaseExpr looks like it's potentially callable with
- // 0 arguments, and that it returns something of a reasonable type, so we
- // can emit a fixit and carry on pretending that BaseExpr was actually a
- // CallExpr.
- SourceLocation ParenInsertionLoc =
- PP.getLocForEndOfToken(BaseExpr.get()->getLocEnd());
- Diag(BaseExpr.get()->getExprLoc(), diag::err_member_reference_needs_call)
- << int(Overloaded) << 1
- << BaseExpr.get()->getSourceRange()
- << FixItHint::CreateInsertion(ParenInsertionLoc, "()");
- ExprResult NewBase = ActOnCallExpr(0, BaseExpr.take(), ParenInsertionLoc,
- MultiExprArg(*this, 0, 0),
- ParenInsertionLoc);
- if (NewBase.isInvalid())
- return ExprError();
- BaseExpr = NewBase;
- BaseExpr = DefaultFunctionArrayConversion(BaseExpr.take());
- return LookupMemberExpr(R, BaseExpr, IsArrow, OpLoc, SS,
- ObjCImpDecl, HasTemplateArgs);
- }
-
Diag(MemberLoc, diag::err_typecheck_member_reference_struct_union)
<< BaseType << BaseExpr.get()->getSourceRange();
@@ -4946,6 +5011,26 @@ Sema::ActOnCUDAExecConfigExpr(Scope *S, SourceLocation LLLLoc,
return ActOnCallExpr(S, ConfigDR, LLLLoc, execConfig, GGGLoc, 0);
}
+/// ActOnAsTypeExpr - create a new asType (bitcast) from the arguments.
+///
+/// __builtin_astype( value, dst type )
+///
+ExprResult Sema::ActOnAsTypeExpr(Expr *expr, ParsedType destty,
+ SourceLocation BuiltinLoc,
+ SourceLocation RParenLoc) {
+ ExprValueKind VK = VK_RValue;
+ ExprObjectKind OK = OK_Ordinary;
+ QualType DstTy = GetTypeFromParser(destty);
+ QualType SrcTy = expr->getType();
+ if (Context.getTypeSize(DstTy) != Context.getTypeSize(SrcTy))
+ return ExprError(Diag(BuiltinLoc,
+ diag::err_invalid_astype_of_different_size)
+ << DstTy
+ << SrcTy
+ << expr->getSourceRange());
+ return Owned(new (Context) AsTypeExpr(expr, DstTy, VK, OK, BuiltinLoc, RParenLoc));
+}
+
/// BuildResolvedCallExpr - Build a call to a resolved expression,
/// i.e. an expression not of \p OverloadTy. The expression should
/// unary-convert to an expression of function-pointer or
@@ -6118,6 +6203,150 @@ QualType Sema::FindCompositeObjCPointerType(ExprResult &LHS, ExprResult &RHS,
return QualType();
}
+/// SuggestParentheses - Emit a diagnostic together with a fixit hint that wraps
+/// ParenRange in parentheses.
+static void SuggestParentheses(Sema &Self, SourceLocation Loc,
+ const PartialDiagnostic &PD,
+ const PartialDiagnostic &FirstNote,
+ SourceRange FirstParenRange,
+ const PartialDiagnostic &SecondNote,
+ SourceRange SecondParenRange) {
+ Self.Diag(Loc, PD);
+
+ if (!FirstNote.getDiagID())
+ return;
+
+ SourceLocation EndLoc = Self.PP.getLocForEndOfToken(FirstParenRange.getEnd());
+ if (!FirstParenRange.getEnd().isFileID() || EndLoc.isInvalid()) {
+ // We can't display the parentheses, so just return.
+ return;
+ }
+
+ Self.Diag(Loc, FirstNote)
+ << FixItHint::CreateInsertion(FirstParenRange.getBegin(), "(")
+ << FixItHint::CreateInsertion(EndLoc, ")");
+
+ if (!SecondNote.getDiagID())
+ return;
+
+ EndLoc = Self.PP.getLocForEndOfToken(SecondParenRange.getEnd());
+ if (!SecondParenRange.getEnd().isFileID() || EndLoc.isInvalid()) {
+ // We can't display the parentheses, so just dig the
+ // warning/error and return.
+ Self.Diag(Loc, SecondNote);
+ return;
+ }
+
+ Self.Diag(Loc, SecondNote)
+ << FixItHint::CreateInsertion(SecondParenRange.getBegin(), "(")
+ << FixItHint::CreateInsertion(EndLoc, ")");
+}
+
+static bool IsArithmeticOp(BinaryOperatorKind Opc) {
+ return Opc >= BO_Mul && Opc <= BO_Shr;
+}
+
+/// IsArithmeticBinaryExpr - Returns true if E is an arithmetic binary
+/// expression, either using a built-in or overloaded operator,
+/// and sets *OpCode to the opcode and *RHS to the right-hand side expression.
+static bool IsArithmeticBinaryExpr(Expr *E, BinaryOperatorKind *Opcode,
+ Expr **RHS) {
+ E = E->IgnoreParenImpCasts();
+ E = E->IgnoreConversionOperator();
+ E = E->IgnoreParenImpCasts();
+
+ // Built-in binary operator.
+ if (BinaryOperator *OP = dyn_cast<BinaryOperator>(E)) {
+ if (IsArithmeticOp(OP->getOpcode())) {
+ *Opcode = OP->getOpcode();
+ *RHS = OP->getRHS();
+ return true;
+ }
+ }
+
+ // Overloaded operator.
+ if (CXXOperatorCallExpr *Call = dyn_cast<CXXOperatorCallExpr>(E)) {
+ if (Call->getNumArgs() != 2)
+ return false;
+
+ // Make sure this is really a binary operator that is safe to pass into
+ // BinaryOperator::getOverloadedOpcode(), e.g. it's not a subscript op.
+ OverloadedOperatorKind OO = Call->getOperator();
+ if (OO < OO_Plus || OO > OO_Arrow)
+ return false;
+
+ BinaryOperatorKind OpKind = BinaryOperator::getOverloadedOpcode(OO);
+ if (IsArithmeticOp(OpKind)) {
+ *Opcode = OpKind;
+ *RHS = Call->getArg(1);
+ return true;
+ }
+ }
+
+ return false;
+}
+
+static bool IsLogicOp(BinaryOperatorKind Opc) {
+ return (Opc >= BO_LT && Opc <= BO_NE) || (Opc >= BO_LAnd && Opc <= BO_LOr);
+}
+
+/// ExprLooksBoolean - Returns true if E looks boolean, i.e. it has boolean type
+/// or is a logical expression such as (x==y) which has int type, but is
+/// commonly interpreted as boolean.
+static bool ExprLooksBoolean(Expr *E) {
+ E = E->IgnoreParenImpCasts();
+
+ if (E->getType()->isBooleanType())
+ return true;
+ if (BinaryOperator *OP = dyn_cast<BinaryOperator>(E))
+ return IsLogicOp(OP->getOpcode());
+ if (UnaryOperator *OP = dyn_cast<UnaryOperator>(E))
+ return OP->getOpcode() == UO_LNot;
+
+ return false;
+}
+
+/// DiagnoseConditionalPrecedence - Emit a warning when a conditional operator
+/// and binary operator are mixed in a way that suggests the programmer assumed
+/// the conditional operator has higher precedence, for example:
+/// "int x = a + someBinaryCondition ? 1 : 2".
+static void DiagnoseConditionalPrecedence(Sema &Self,
+ SourceLocation OpLoc,
+ Expr *cond,
+ Expr *lhs,
+ Expr *rhs) {
+ BinaryOperatorKind CondOpcode;
+ Expr *CondRHS;
+
+ if (!IsArithmeticBinaryExpr(cond, &CondOpcode, &CondRHS))
+ return;
+ if (!ExprLooksBoolean(CondRHS))
+ return;
+
+ // The condition is an arithmetic binary expression, with a right-
+ // hand side that looks boolean, so warn.
+
+ PartialDiagnostic Warn = Self.PDiag(diag::warn_precedence_conditional)
+ << cond->getSourceRange()
+ << BinaryOperator::getOpcodeStr(CondOpcode);
+
+ PartialDiagnostic FirstNote =
+ Self.PDiag(diag::note_precedence_conditional_silence)
+ << BinaryOperator::getOpcodeStr(CondOpcode);
+
+ SourceRange FirstParenRange(cond->getLocStart(),
+ cond->getLocEnd());
+
+ PartialDiagnostic SecondNote =
+ Self.PDiag(diag::note_precedence_conditional_first);
+
+ SourceRange SecondParenRange(CondRHS->getLocStart(),
+ rhs->getLocEnd());
+
+ SuggestParentheses(Self, OpLoc, Warn, FirstNote, FirstParenRange,
+ SecondNote, SecondParenRange);
+}
+
/// ActOnConditionalOp - Parse a ?: operation. Note that 'LHS' may be null
/// in the case of a the GNU conditional expr extension.
ExprResult Sema::ActOnConditionalOp(SourceLocation QuestionLoc,
@@ -6162,6 +6391,9 @@ ExprResult Sema::ActOnConditionalOp(SourceLocation QuestionLoc,
RHS.isInvalid())
return ExprError();
+ DiagnoseConditionalPrecedence(*this, QuestionLoc, Cond.get(), LHS.get(),
+ RHS.get());
+
if (!commonExpr)
return Owned(new (Context) ConditionalOperator(Cond.take(), QuestionLoc,
LHS.take(), ColonLoc,
@@ -7487,7 +7719,7 @@ QualType Sema::CheckCompareOperands(ExprResult &lex, ExprResult &rex, SourceLoca
// Comparison of pointers with null pointer constants and equality
// comparisons of member pointers to null pointer constants.
if (RHSIsNull &&
- ((lType->isPointerType() || lType->isNullPtrType()) ||
+ ((lType->isAnyPointerType() || lType->isNullPtrType()) ||
(!isRelational && lType->isMemberPointerType()))) {
rex = ImpCastExprToType(rex.take(), lType,
lType->isMemberPointerType()
@@ -7496,7 +7728,7 @@ QualType Sema::CheckCompareOperands(ExprResult &lex, ExprResult &rex, SourceLoca
return ResultTy;
}
if (LHSIsNull &&
- ((rType->isPointerType() || rType->isNullPtrType()) ||
+ ((rType->isAnyPointerType() || rType->isNullPtrType()) ||
(!isRelational && rType->isMemberPointerType()))) {
lex = ImpCastExprToType(lex.take(), rType,
rType->isMemberPointerType()
@@ -7748,13 +7980,15 @@ inline QualType Sema::CheckLogicalOperands( // C99 6.5.[13,14]
// If the RHS can be constant folded, and if it constant folds to something
// that isn't 0 or 1 (which indicate a potential logical operation that
// happened to fold to true/false) then warn.
+ // Parens on the RHS are ignored.
Expr::EvalResult Result;
- if (rex.get()->Evaluate(Result, Context) && !Result.HasSideEffects &&
- Result.Val.getInt() != 0 && Result.Val.getInt() != 1) {
- Diag(Loc, diag::warn_logical_instead_of_bitwise)
- << rex.get()->getSourceRange()
- << (Opc == BO_LAnd ? "&&" : "||")
- << (Opc == BO_LAnd ? "&" : "|");
+ if (rex.get()->Evaluate(Result, Context) && !Result.HasSideEffects)
+ if ((getLangOptions().Bool && !rex.get()->getType()->isBooleanType()) ||
+ (Result.Val.getInt() != 0 && Result.Val.getInt() != 1)) {
+ Diag(Loc, diag::warn_logical_instead_of_bitwise)
+ << rex.get()->getSourceRange()
+ << (Opc == BO_LAnd ? "&&" : "||")
+ << (Opc == BO_LAnd ? "&" : "|");
}
}
@@ -8127,20 +8361,31 @@ ExprResult Sema::ConvertPropertyForRValue(Expr *E) {
E->getObjectKind() == OK_ObjCProperty);
const ObjCPropertyRefExpr *PRE = E->getObjCProperty();
+ QualType T = E->getType();
+ QualType ReceiverType;
+ if (PRE->isObjectReceiver())
+ ReceiverType = PRE->getBase()->getType();
+ else if (PRE->isSuperReceiver())
+ ReceiverType = PRE->getSuperReceiverType();
+ else
+ ReceiverType = Context.getObjCInterfaceType(PRE->getClassReceiver());
+
ExprValueKind VK = VK_RValue;
if (PRE->isImplicitProperty()) {
- if (const ObjCMethodDecl *GetterMethod =
+ if (ObjCMethodDecl *GetterMethod =
PRE->getImplicitPropertyGetter()) {
- QualType Result = GetterMethod->getResultType();
- VK = Expr::getValueKindForType(Result);
+ T = getMessageSendResultType(ReceiverType, GetterMethod,
+ PRE->isClassReceiver(),
+ PRE->isSuperReceiver());
+ VK = Expr::getValueKindForType(GetterMethod->getResultType());
}
else {
Diag(PRE->getLocation(), diag::err_getter_not_found)
<< PRE->getBase()->getType();
}
}
-
- E = ImplicitCastExpr::Create(Context, E->getType(), CK_GetObjCProperty,
+
+ E = ImplicitCastExpr::Create(Context, T, CK_GetObjCProperty,
E, 0, VK);
ExprResult Result = MaybeBindToTemporary(E);
@@ -8404,7 +8649,13 @@ static QualType CheckIndirectionOperand(Sema &S, Expr *Op, ExprValueKind &VK,
Op = ConvResult.take();
QualType OpTy = Op->getType();
QualType Result;
-
+
+ if (isa<CXXReinterpretCastExpr>(Op)) {
+ QualType OpOrigType = Op->IgnoreParenCasts()->getType();
+ S.CheckCompatibleReinterpretCast(OpOrigType, OpTy, /*IsDereference*/true,
+ Op->getSourceRange());
+ }
+
// Note that per both C89 and C99, indirection is always legal, even if OpTy
// is an incomplete type or void. It would be possible to warn about
// dereferencing a void pointer, but it's completely well-defined, and such a
@@ -8678,45 +8929,6 @@ ExprResult Sema::CreateBuiltinBinOp(SourceLocation OpLoc,
CompResultTy, OpLoc));
}
-/// SuggestParentheses - Emit a diagnostic together with a fixit hint that wraps
-/// ParenRange in parentheses.
-static void SuggestParentheses(Sema &Self, SourceLocation Loc,
- const PartialDiagnostic &PD,
- const PartialDiagnostic &FirstNote,
- SourceRange FirstParenRange,
- const PartialDiagnostic &SecondNote,
- SourceRange SecondParenRange) {
- Self.Diag(Loc, PD);
-
- if (!FirstNote.getDiagID())
- return;
-
- SourceLocation EndLoc = Self.PP.getLocForEndOfToken(FirstParenRange.getEnd());
- if (!FirstParenRange.getEnd().isFileID() || EndLoc.isInvalid()) {
- // We can't display the parentheses, so just return.
- return;
- }
-
- Self.Diag(Loc, FirstNote)
- << FixItHint::CreateInsertion(FirstParenRange.getBegin(), "(")
- << FixItHint::CreateInsertion(EndLoc, ")");
-
- if (!SecondNote.getDiagID())
- return;
-
- EndLoc = Self.PP.getLocForEndOfToken(SecondParenRange.getEnd());
- if (!SecondParenRange.getEnd().isFileID() || EndLoc.isInvalid()) {
- // We can't display the parentheses, so just dig the
- // warning/error and return.
- Self.Diag(Loc, SecondNote);
- return;
- }
-
- Self.Diag(Loc, SecondNote)
- << FixItHint::CreateInsertion(SecondParenRange.getBegin(), "(")
- << FixItHint::CreateInsertion(EndLoc, ")");
-}
-
/// DiagnoseBitwisePrecedence - Emit a warning when bitwise and comparison
/// operators are mixed in a way that suggests that the programmer forgot that
/// comparison operators have higher precedence. The most typical example of
@@ -9666,6 +9878,7 @@ bool Sema::DiagnoseAssignmentResult(AssignConvertType ConvTy,
*Complained = false;
// Decode the result (notice that AST's are still created for extensions).
+ bool CheckInferredResultType = false;
bool isInvalid = false;
unsigned DiagKind;
FixItHint Hint;
@@ -9682,6 +9895,8 @@ bool Sema::DiagnoseAssignmentResult(AssignConvertType ConvTy,
case IncompatiblePointer:
MakeObjCStringLiteralFixItHint(*this, DstType, SrcExpr, Hint);
DiagKind = diag::ext_typecheck_convert_incompatible_pointer;
+ CheckInferredResultType = DstType->isObjCObjectPointerType() &&
+ SrcType->isObjCObjectPointerType();
break;
case IncompatiblePointerSign:
DiagKind = diag::ext_typecheck_convert_incompatible_pointer_sign;
@@ -9763,6 +9978,9 @@ bool Sema::DiagnoseAssignmentResult(AssignConvertType ConvTy,
Diag(Loc, DiagKind) << FirstType << SecondType << Action
<< SrcExpr->getSourceRange() << Hint;
+ if (CheckInferredResultType)
+ EmitRelatedResultTypeNote(SrcExpr);
+
if (Complained)
*Complained = true;
return isInvalid;
@@ -9914,26 +10132,25 @@ void Sema::MarkDeclarationReferenced(SourceLocation Loc, Decl *D) {
// Note that this declaration has been used.
if (CXXConstructorDecl *Constructor = dyn_cast<CXXConstructorDecl>(D)) {
- unsigned TypeQuals;
- if (Constructor->isImplicit() && Constructor->isDefaultConstructor()) {
- if (Constructor->getParent()->hasTrivialConstructor())
+ if (Constructor->isDefaulted() && Constructor->isDefaultConstructor()) {
+ if (Constructor->isTrivial())
return;
if (!Constructor->isUsed(false))
DefineImplicitDefaultConstructor(Loc, Constructor);
- } else if (Constructor->isImplicit() &&
- Constructor->isCopyConstructor(TypeQuals)) {
+ } else if (Constructor->isDefaulted() &&
+ Constructor->isCopyConstructor()) {
if (!Constructor->isUsed(false))
- DefineImplicitCopyConstructor(Loc, Constructor, TypeQuals);
+ DefineImplicitCopyConstructor(Loc, Constructor);
}
MarkVTableUsed(Loc, Constructor->getParent());
} else if (CXXDestructorDecl *Destructor = dyn_cast<CXXDestructorDecl>(D)) {
- if (Destructor->isImplicit() && !Destructor->isUsed(false))
+ if (Destructor->isDefaulted() && !Destructor->isUsed(false))
DefineImplicitDestructor(Loc, Destructor);
if (Destructor->isVirtual())
MarkVTableUsed(Loc, Destructor->getParent());
} else if (CXXMethodDecl *MethodDecl = dyn_cast<CXXMethodDecl>(D)) {
- if (MethodDecl->isImplicit() && MethodDecl->isOverloadedOperator() &&
+ if (MethodDecl->isDefaulted() && MethodDecl->isOverloadedOperator() &&
MethodDecl->getOverloadedOperator() == OO_Equal) {
if (!MethodDecl->isUsed(false))
DefineImplicitCopyAssignment(Loc, MethodDecl);
diff --git a/lib/Sema/SemaExprCXX.cpp b/lib/Sema/SemaExprCXX.cpp
index 7f1bf59..2f5a890 100644
--- a/lib/Sema/SemaExprCXX.cpp
+++ b/lib/Sema/SemaExprCXX.cpp
@@ -17,6 +17,7 @@
#include "clang/Sema/Lookup.h"
#include "clang/Sema/ParsedTemplate.h"
#include "clang/Sema/ScopeInfo.h"
+#include "clang/Sema/Scope.h"
#include "clang/Sema/TemplateDeduction.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/CXXInheritance.h"
@@ -385,13 +386,14 @@ static UuidAttr *GetUuidAttrOfType(QualType QT) {
else if (QT->isArrayType())
Ty = cast<ArrayType>(QT)->getElementType().getTypePtr();
- // Loop all class definition and declaration looking for an uuid attribute.
+ // Loop all record redeclaration looking for an uuid attribute.
CXXRecordDecl *RD = Ty->getAsCXXRecordDecl();
- while (RD) {
- if (UuidAttr *Uuid = RD->getAttr<UuidAttr>())
+ for (CXXRecordDecl::redecl_iterator I = RD->redecls_begin(),
+ E = RD->redecls_end(); I != E; ++I) {
+ if (UuidAttr *Uuid = I->getAttr<UuidAttr>())
return Uuid;
- RD = RD->getPreviousDeclaration();
}
+
return 0;
}
@@ -574,42 +576,54 @@ ExprResult Sema::CheckCXXThrowOperand(SourceLocation ThrowLoc, Expr *E) {
return Owned(E);
}
-CXXMethodDecl *Sema::tryCaptureCXXThis() {
+QualType Sema::getAndCaptureCurrentThisType() {
// Ignore block scopes: we can capture through them.
// Ignore nested enum scopes: we'll diagnose non-constant expressions
// where they're invalid, and other uses are legitimate.
// Don't ignore nested class scopes: you can't use 'this' in a local class.
DeclContext *DC = CurContext;
+ unsigned NumBlocks = 0;
while (true) {
- if (isa<BlockDecl>(DC)) DC = cast<BlockDecl>(DC)->getDeclContext();
- else if (isa<EnumDecl>(DC)) DC = cast<EnumDecl>(DC)->getDeclContext();
+ if (isa<BlockDecl>(DC)) {
+ DC = cast<BlockDecl>(DC)->getDeclContext();
+ ++NumBlocks;
+ } else if (isa<EnumDecl>(DC))
+ DC = cast<EnumDecl>(DC)->getDeclContext();
else break;
}
- // If we're not in an instance method, error out.
- CXXMethodDecl *method = dyn_cast<CXXMethodDecl>(DC);
- if (!method || !method->isInstance())
- return 0;
+ QualType ThisTy;
+ if (CXXMethodDecl *method = dyn_cast<CXXMethodDecl>(DC)) {
+ if (method && method->isInstance())
+ ThisTy = method->getThisType(Context);
+ } else if (CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(DC)) {
+ // C++0x [expr.prim]p4:
+ // Otherwise, if a member-declarator declares a non-static data member
+ // of a class X, the expression this is a prvalue of type "pointer to X"
+ // within the optional brace-or-equal-initializer.
+ Scope *S = getScopeForContext(DC);
+ if (!S || S->getFlags() & Scope::ThisScope)
+ ThisTy = Context.getPointerType(Context.getRecordType(RD));
+ }
- // Mark that we're closing on 'this' in all the block scopes, if applicable.
- for (unsigned idx = FunctionScopes.size() - 1;
- isa<BlockScopeInfo>(FunctionScopes[idx]);
- --idx)
- cast<BlockScopeInfo>(FunctionScopes[idx])->CapturesCXXThis = true;
+ // Mark that we're closing on 'this' in all the block scopes we ignored.
+ if (!ThisTy.isNull())
+ for (unsigned idx = FunctionScopes.size() - 1;
+ NumBlocks; --idx, --NumBlocks)
+ cast<BlockScopeInfo>(FunctionScopes[idx])->CapturesCXXThis = true;
- return method;
+ return ThisTy;
}
-ExprResult Sema::ActOnCXXThis(SourceLocation loc) {
+ExprResult Sema::ActOnCXXThis(SourceLocation Loc) {
/// C++ 9.3.2: In the body of a non-static member function, the keyword this
/// is a non-lvalue expression whose value is the address of the object for
/// which the function is called.
- CXXMethodDecl *method = tryCaptureCXXThis();
- if (!method) return Diag(loc, diag::err_invalid_this_use);
+ QualType ThisTy = getAndCaptureCurrentThisType();
+ if (ThisTy.isNull()) return Diag(Loc, diag::err_invalid_this_use);
- return Owned(new (Context) CXXThisExpr(loc, method->getThisType(Context),
- /*isImplicit=*/false));
+ return Owned(new (Context) CXXThisExpr(Loc, ThisTy, /*isImplicit=*/false));
}
ExprResult
@@ -950,8 +964,8 @@ Sema::BuildCXXNew(SourceLocation StartLoc, bool UseGlobal,
}
}
- ArraySize = ImpCastExprToType(ArraySize, Context.getSizeType(),
- CK_IntegralCast).take();
+ // Note that we do *not* convert the argument in any way. It can
+ // be signed, larger than size_t, whatever.
}
FunctionDecl *OperatorNew = 0;
@@ -1326,11 +1340,12 @@ bool Sema::FindAllocationFunctions(SourceLocation StartLoc, SourceRange Range,
bool Sema::FindAllocationOverload(SourceLocation StartLoc, SourceRange Range,
DeclarationName Name, Expr** Args,
unsigned NumArgs, DeclContext *Ctx,
- bool AllowMissing, FunctionDecl *&Operator) {
+ bool AllowMissing, FunctionDecl *&Operator,
+ bool Diagnose) {
LookupResult R(*this, Name, StartLoc, LookupOrdinaryName);
LookupQualifiedName(R, Ctx);
if (R.empty()) {
- if (AllowMissing)
+ if (AllowMissing || !Diagnose)
return false;
return Diag(StartLoc, diag::err_ovl_no_viable_function_in_call)
<< Name << Range;
@@ -1374,41 +1389,50 @@ bool Sema::FindAllocationOverload(SourceLocation StartLoc, SourceRange Range,
// Watch out for variadic allocator function.
unsigned NumArgsInFnDecl = FnDecl->getNumParams();
for (unsigned i = 0; (i < NumArgs && i < NumArgsInFnDecl); ++i) {
+ InitializedEntity Entity = InitializedEntity::InitializeParameter(Context,
+ FnDecl->getParamDecl(i));
+
+ if (!Diagnose && !CanPerformCopyInitialization(Entity, Owned(Args[i])))
+ return true;
+
ExprResult Result
- = PerformCopyInitialization(InitializedEntity::InitializeParameter(
- Context,
- FnDecl->getParamDecl(i)),
- SourceLocation(),
- Owned(Args[i]));
+ = PerformCopyInitialization(Entity, SourceLocation(), Owned(Args[i]));
if (Result.isInvalid())
return true;
Args[i] = Result.takeAs<Expr>();
}
Operator = FnDecl;
- CheckAllocationAccess(StartLoc, Range, R.getNamingClass(), Best->FoundDecl);
+ CheckAllocationAccess(StartLoc, Range, R.getNamingClass(), Best->FoundDecl,
+ Diagnose);
return false;
}
case OR_No_Viable_Function:
- Diag(StartLoc, diag::err_ovl_no_viable_function_in_call)
- << Name << Range;
- Candidates.NoteCandidates(*this, OCD_AllCandidates, Args, NumArgs);
+ if (Diagnose) {
+ Diag(StartLoc, diag::err_ovl_no_viable_function_in_call)
+ << Name << Range;
+ Candidates.NoteCandidates(*this, OCD_AllCandidates, Args, NumArgs);
+ }
return true;
case OR_Ambiguous:
- Diag(StartLoc, diag::err_ovl_ambiguous_call)
- << Name << Range;
- Candidates.NoteCandidates(*this, OCD_ViableCandidates, Args, NumArgs);
+ if (Diagnose) {
+ Diag(StartLoc, diag::err_ovl_ambiguous_call)
+ << Name << Range;
+ Candidates.NoteCandidates(*this, OCD_ViableCandidates, Args, NumArgs);
+ }
return true;
case OR_Deleted: {
- Diag(StartLoc, diag::err_ovl_deleted_call)
- << Best->Function->isDeleted()
- << Name
- << getDeletedOrUnavailableSuffix(Best->Function)
- << Range;
- Candidates.NoteCandidates(*this, OCD_AllCandidates, Args, NumArgs);
+ if (Diagnose) {
+ Diag(StartLoc, diag::err_ovl_deleted_call)
+ << Best->Function->isDeleted()
+ << Name
+ << getDeletedOrUnavailableSuffix(Best->Function)
+ << Range;
+ Candidates.NoteCandidates(*this, OCD_AllCandidates, Args, NumArgs);
+ }
return true;
}
}
@@ -1568,7 +1592,7 @@ void Sema::DeclareGlobalAllocationFunction(DeclarationName Name,
bool Sema::FindDeallocationFunction(SourceLocation StartLoc, CXXRecordDecl *RD,
DeclarationName Name,
- FunctionDecl* &Operator) {
+ FunctionDecl* &Operator, bool Diagnose) {
LookupResult Found(*this, Name, StartLoc, LookupOrdinaryName);
// Try to find operator delete/operator delete[] in class scope.
LookupQualifiedName(Found, RD);
@@ -1595,33 +1619,45 @@ bool Sema::FindDeallocationFunction(SourceLocation StartLoc, CXXRecordDecl *RD,
// There's exactly one suitable operator; pick it.
if (Matches.size() == 1) {
Operator = cast<CXXMethodDecl>(Matches[0]->getUnderlyingDecl());
+
+ if (Operator->isDeleted()) {
+ if (Diagnose) {
+ Diag(StartLoc, diag::err_deleted_function_use);
+ Diag(Operator->getLocation(), diag::note_unavailable_here) << true;
+ }
+ return true;
+ }
+
CheckAllocationAccess(StartLoc, SourceRange(), Found.getNamingClass(),
- Matches[0]);
+ Matches[0], Diagnose);
return false;
// We found multiple suitable operators; complain about the ambiguity.
} else if (!Matches.empty()) {
- Diag(StartLoc, diag::err_ambiguous_suitable_delete_member_function_found)
- << Name << RD;
-
- for (llvm::SmallVectorImpl<DeclAccessPair>::iterator
- F = Matches.begin(), FEnd = Matches.end(); F != FEnd; ++F)
- Diag((*F)->getUnderlyingDecl()->getLocation(),
- diag::note_member_declared_here) << Name;
+ if (Diagnose) {
+ Diag(StartLoc, diag::err_ambiguous_suitable_delete_member_function_found)
+ << Name << RD;
+
+ for (llvm::SmallVectorImpl<DeclAccessPair>::iterator
+ F = Matches.begin(), FEnd = Matches.end(); F != FEnd; ++F)
+ Diag((*F)->getUnderlyingDecl()->getLocation(),
+ diag::note_member_declared_here) << Name;
+ }
return true;
}
// We did find operator delete/operator delete[] declarations, but
// none of them were suitable.
if (!Found.empty()) {
- Diag(StartLoc, diag::err_no_suitable_delete_member_function_found)
- << Name << RD;
-
- for (LookupResult::iterator F = Found.begin(), FEnd = Found.end();
- F != FEnd; ++F)
- Diag((*F)->getUnderlyingDecl()->getLocation(),
- diag::note_member_declared_here) << Name;
-
+ if (Diagnose) {
+ Diag(StartLoc, diag::err_no_suitable_delete_member_function_found)
+ << Name << RD;
+
+ for (LookupResult::iterator F = Found.begin(), FEnd = Found.end();
+ F != FEnd; ++F)
+ Diag((*F)->getUnderlyingDecl()->getLocation(),
+ diag::note_member_declared_here) << Name;
+ }
return true;
}
@@ -1633,8 +1669,8 @@ bool Sema::FindDeallocationFunction(SourceLocation StartLoc, CXXRecordDecl *RD,
Expr* DeallocArgs[1];
DeallocArgs[0] = &Null;
if (FindAllocationOverload(StartLoc, SourceRange(), Name,
- DeallocArgs, 1, TUDecl, /*AllowMissing=*/false,
- Operator))
+ DeallocArgs, 1, TUDecl, !Diagnose,
+ Operator, Diagnose))
return true;
assert(Operator && "Did not find a deallocation function!");
@@ -1780,6 +1816,20 @@ Sema::ActOnCXXDelete(SourceLocation StartLoc, bool UseGlobal,
const_cast<CXXDestructorDecl*>(Dtor));
DiagnoseUseOfDecl(Dtor, StartLoc);
}
+
+ // C++ [expr.delete]p3:
+ // In the first alternative (delete object), if the static type of the
+ // object to be deleted is different from its dynamic type, the static
+ // type shall be a base class of the dynamic type of the object to be
+ // deleted and the static type shall have a virtual destructor or the
+ // behavior is undefined.
+ //
+ // Note: a final class cannot be derived from, no issue there
+ if (!ArrayForm && RD->isPolymorphic() && !RD->hasAttr<FinalAttr>()) {
+ CXXDestructorDecl *dtor = RD->getDestructor();
+ if (!dtor || !dtor->isVirtual())
+ Diag(StartLoc, diag::warn_delete_non_virtual_dtor) << PointeeElem;
+ }
}
if (!OperatorDelete) {
@@ -2174,7 +2224,7 @@ Sema::PerformImplicitConversion(Expr *From, QualType ToType,
case ICK_Pointer_Conversion: {
if (SCS.IncompatibleObjC && Action != AA_Casting) {
// Diagnose incompatible Objective-C conversions
- if (Action == AA_Initializing)
+ if (Action == AA_Initializing || Action == AA_Assigning)
Diag(From->getSourceRange().getBegin(),
diag::ext_typecheck_convert_incompatible_pointer)
<< ToType << From->getType() << Action
@@ -2184,6 +2234,10 @@ Sema::PerformImplicitConversion(Expr *From, QualType ToType,
diag::ext_typecheck_convert_incompatible_pointer)
<< From->getType() << ToType << Action
<< From->getSourceRange();
+
+ if (From->getType()->isObjCObjectPointerType() &&
+ ToType->isObjCObjectPointerType())
+ EmitRelatedResultTypeNote(From);
}
CastKind Kind = CK_Invalid;
@@ -2416,6 +2470,7 @@ static bool CheckUnaryTypeTraitTypeCompleteness(Sema &S,
// C++0x [meta.unary.prop] Table 49 requires the following traits to be
// applied to a complete type.
case UTT_IsTrivial:
+ case UTT_IsTriviallyCopyable:
case UTT_IsStandardLayout:
case UTT_IsPOD:
case UTT_IsLiteral:
@@ -2433,7 +2488,7 @@ static bool CheckUnaryTypeTraitTypeCompleteness(Sema &S,
case UTT_HasNothrowConstructor:
case UTT_HasNothrowCopy:
case UTT_HasTrivialAssign:
- case UTT_HasTrivialConstructor:
+ case UTT_HasTrivialDefaultConstructor:
case UTT_HasTrivialCopy:
case UTT_HasTrivialDestructor:
case UTT_HasVirtualDestructor:
@@ -2512,6 +2567,8 @@ static bool EvaluateUnaryTypeTrait(Sema &Self, UnaryTypeTrait UTT,
return T.isVolatileQualified();
case UTT_IsTrivial:
return T->isTrivialType();
+ case UTT_IsTriviallyCopyable:
+ return T->isTriviallyCopyableType();
case UTT_IsStandardLayout:
return T->isStandardLayoutType();
case UTT_IsPOD:
@@ -2543,7 +2600,7 @@ static bool EvaluateUnaryTypeTrait(Sema &Self, UnaryTypeTrait UTT,
//
// 1: http://gcc.gnu/.org/onlinedocs/gcc/Type-Traits.html
// 2: http://docwiki.embarcadero.com/RADStudio/XE/en/Type_Trait_Functions_(C%2B%2B0x)_Index
- case UTT_HasTrivialConstructor:
+ case UTT_HasTrivialDefaultConstructor:
// http://gcc.gnu.org/onlinedocs/gcc/Type-Traits.html:
// If __is_pod (type) is true then the trait is true, else if type is
// a cv class or union type (or array thereof) with a trivial default
@@ -2552,7 +2609,7 @@ static bool EvaluateUnaryTypeTrait(Sema &Self, UnaryTypeTrait UTT,
return true;
if (const RecordType *RT =
C.getBaseElementType(T)->getAs<RecordType>())
- return cast<CXXRecordDecl>(RT->getDecl())->hasTrivialConstructor();
+ return cast<CXXRecordDecl>(RT->getDecl())->hasTrivialDefaultConstructor();
return false;
case UTT_HasTrivialCopy:
// http://gcc.gnu.org/onlinedocs/gcc/Type-Traits.html:
@@ -2619,7 +2676,6 @@ static bool EvaluateUnaryTypeTrait(Sema &Self, UnaryTypeTrait UTT,
return true;
bool FoundAssign = false;
- bool AllNoThrow = true;
DeclarationName Name = C.DeclarationNames.getCXXOperatorName(OO_Equal);
LookupResult Res(Self, DeclarationNameInfo(Name, KeyLoc),
Sema::LookupOrdinaryName);
@@ -2631,15 +2687,15 @@ static bool EvaluateUnaryTypeTrait(Sema &Self, UnaryTypeTrait UTT,
FoundAssign = true;
const FunctionProtoType *CPT
= Operator->getType()->getAs<FunctionProtoType>();
- if (!CPT->isNothrow(Self.Context)) {
- AllNoThrow = false;
- break;
- }
+ if (CPT->getExceptionSpecType() == EST_Delayed)
+ return false;
+ if (!CPT->isNothrow(Self.Context))
+ return false;
}
}
}
- return FoundAssign && AllNoThrow;
+ return FoundAssign;
}
return false;
case UTT_HasNothrowCopy:
@@ -2656,7 +2712,6 @@ static bool EvaluateUnaryTypeTrait(Sema &Self, UnaryTypeTrait UTT,
return true;
bool FoundConstructor = false;
- bool AllNoThrow = true;
unsigned FoundTQs;
DeclContext::lookup_const_iterator Con, ConEnd;
for (llvm::tie(Con, ConEnd) = Self.LookupConstructors(RD);
@@ -2671,16 +2726,16 @@ static bool EvaluateUnaryTypeTrait(Sema &Self, UnaryTypeTrait UTT,
FoundConstructor = true;
const FunctionProtoType *CPT
= Constructor->getType()->getAs<FunctionProtoType>();
+ if (CPT->getExceptionSpecType() == EST_Delayed)
+ return false;
// FIXME: check whether evaluating default arguments can throw.
// For now, we'll be conservative and assume that they can throw.
- if (!CPT->isNothrow(Self.Context) || CPT->getNumArgs() > 1) {
- AllNoThrow = false;
- break;
- }
+ if (!CPT->isNothrow(Self.Context) || CPT->getNumArgs() > 1)
+ return false;
}
}
- return FoundConstructor && AllNoThrow;
+ return FoundConstructor;
}
return false;
case UTT_HasNothrowConstructor:
@@ -2693,7 +2748,7 @@ static bool EvaluateUnaryTypeTrait(Sema &Self, UnaryTypeTrait UTT,
return true;
if (const RecordType *RT = C.getBaseElementType(T)->getAs<RecordType>()) {
CXXRecordDecl *RD = cast<CXXRecordDecl>(RT->getDecl());
- if (RD->hasTrivialConstructor())
+ if (RD->hasTrivialDefaultConstructor())
return true;
DeclContext::lookup_const_iterator Con, ConEnd;
@@ -2706,6 +2761,8 @@ static bool EvaluateUnaryTypeTrait(Sema &Self, UnaryTypeTrait UTT,
if (Constructor->isDefaultConstructor()) {
const FunctionProtoType *CPT
= Constructor->getType()->getAs<FunctionProtoType>();
+ if (CPT->getExceptionSpecType() == EST_Delayed)
+ return false;
// TODO: check whether evaluating default arguments can throw.
// For now, we'll be conservative and assume that they can throw.
return CPT->isNothrow(Self.Context) && CPT->getNumArgs() == 0;
@@ -2852,7 +2909,7 @@ static bool EvaluateBinaryTypeTrait(Sema &Self, BinaryTypeTrait BTT,
Sema::SFINAETrap SFINAE(Self, /*AccessCheckingSFINAE=*/true);
Sema::ContextRAII TUContext(Self, Self.Context.getTranslationUnitDecl());
InitializationSequence Init(Self, To, Kind, &FromPtr, 1);
- if (Init.getKind() == InitializationSequence::FailedSequence)
+ if (Init.Failed())
return false;
ExprResult Result = Init.Perform(Self, To, Kind, MultiExprArg(&FromPtr, 1));
@@ -3213,7 +3270,7 @@ static bool TryClassUnification(Sema &Self, Expr *From, Expr *To,
if (TTy.isAtLeastAsQualifiedAs(FTy)) {
InitializedEntity Entity = InitializedEntity::InitializeTemporary(TTy);
InitializationSequence InitSeq(Self, Entity, Kind, &From, 1);
- if (InitSeq.getKind() != InitializationSequence::FailedSequence) {
+ if (InitSeq) {
HaveConversion = true;
return false;
}
@@ -3238,7 +3295,7 @@ static bool TryClassUnification(Sema &Self, Expr *From, Expr *To,
InitializedEntity Entity = InitializedEntity::InitializeTemporary(TTy);
InitializationSequence InitSeq(Self, Entity, Kind, &From, 1);
- HaveConversion = InitSeq.getKind() != InitializationSequence::FailedSequence;
+ HaveConversion = !InitSeq.Failed();
ToType = TTy;
if (InitSeq.isAmbiguous())
return InitSeq.Diagnose(Self, Entity, Kind, &From, 1);
@@ -4295,3 +4352,18 @@ StmtResult Sema::ActOnFinishFullStmt(Stmt *FullStmt) {
return MaybeCreateStmtWithCleanups(FullStmt);
}
+
+bool Sema::CheckMicrosoftIfExistsSymbol(CXXScopeSpec &SS,
+ UnqualifiedId &Name) {
+ DeclarationNameInfo TargetNameInfo = GetNameFromUnqualifiedId(Name);
+ DeclarationName TargetName = TargetNameInfo.getName();
+ if (!TargetName)
+ return false;
+
+ // Do the redeclaration lookup in the current scope.
+ LookupResult R(*this, TargetNameInfo, Sema::LookupAnyName,
+ Sema::NotForRedeclaration);
+ R.suppressDiagnostics();
+ LookupParsedName(R, getCurScope(), &SS);
+ return !R.empty();
+}
diff --git a/lib/Sema/SemaExprObjC.cpp b/lib/Sema/SemaExprObjC.cpp
index 2a262f0..cb5c1e0 100644
--- a/lib/Sema/SemaExprObjC.cpp
+++ b/lib/Sema/SemaExprObjC.cpp
@@ -119,7 +119,7 @@ ExprResult Sema::ParseObjCStringLiteral(SourceLocation *AtLocs,
return new (Context) ObjCStringLiteral(S, Ty, AtLocs[0]);
}
-Expr *Sema::BuildObjCEncodeExpression(SourceLocation AtLoc,
+ExprResult Sema::BuildObjCEncodeExpression(SourceLocation AtLoc,
TypeSourceInfo *EncodedTypeInfo,
SourceLocation RParenLoc) {
QualType EncodedType = EncodedTypeInfo->getType();
@@ -127,6 +127,12 @@ Expr *Sema::BuildObjCEncodeExpression(SourceLocation AtLoc,
if (EncodedType->isDependentType())
StrTy = Context.DependentTy;
else {
+ if (!EncodedType->getAsArrayTypeUnsafe()) // Incomplete array is handled.
+ if (RequireCompleteType(AtLoc, EncodedType,
+ PDiag(diag::err_incomplete_type_objc_at_encode)
+ << EncodedTypeInfo->getTypeLoc().getSourceRange()))
+ return ExprError();
+
std::string Str;
Context.getObjCEncodingForType(EncodedType, Str);
@@ -235,10 +241,72 @@ ObjCMethodDecl *Sema::tryCaptureObjCSelf() {
return method;
}
+QualType Sema::getMessageSendResultType(QualType ReceiverType,
+ ObjCMethodDecl *Method,
+ bool isClassMessage, bool isSuperMessage) {
+ assert(Method && "Must have a method");
+ if (!Method->hasRelatedResultType())
+ return Method->getSendResultType();
+
+ // If a method has a related return type:
+ // - if the method found is an instance method, but the message send
+ // was a class message send, T is the declared return type of the method
+ // found
+ if (Method->isInstanceMethod() && isClassMessage)
+ return Method->getSendResultType();
+
+ // - if the receiver is super, T is a pointer to the class of the
+ // enclosing method definition
+ if (isSuperMessage) {
+ if (ObjCMethodDecl *CurMethod = getCurMethodDecl())
+ if (ObjCInterfaceDecl *Class = CurMethod->getClassInterface())
+ return Context.getObjCObjectPointerType(
+ Context.getObjCInterfaceType(Class));
+ }
+
+ // - if the receiver is the name of a class U, T is a pointer to U
+ if (ReceiverType->getAs<ObjCInterfaceType>() ||
+ ReceiverType->isObjCQualifiedInterfaceType())
+ return Context.getObjCObjectPointerType(ReceiverType);
+ // - if the receiver is of type Class or qualified Class type,
+ // T is the declared return type of the method.
+ if (ReceiverType->isObjCClassType() ||
+ ReceiverType->isObjCQualifiedClassType())
+ return Method->getSendResultType();
+
+ // - if the receiver is id, qualified id, Class, or qualified Class, T
+ // is the receiver type, otherwise
+ // - T is the type of the receiver expression.
+ return ReceiverType;
+}
+
+void Sema::EmitRelatedResultTypeNote(const Expr *E) {
+ E = E->IgnoreParenImpCasts();
+ const ObjCMessageExpr *MsgSend = dyn_cast<ObjCMessageExpr>(E);
+ if (!MsgSend)
+ return;
+
+ const ObjCMethodDecl *Method = MsgSend->getMethodDecl();
+ if (!Method)
+ return;
+
+ if (!Method->hasRelatedResultType())
+ return;
+
+ if (Context.hasSameUnqualifiedType(Method->getResultType()
+ .getNonReferenceType(),
+ MsgSend->getType()))
+ return;
+
+ Diag(Method->getLocation(), diag::note_related_result_type_inferred)
+ << Method->isInstanceMethod() << Method->getSelector()
+ << MsgSend->getType();
+}
-bool Sema::CheckMessageArgumentTypes(Expr **Args, unsigned NumArgs,
+bool Sema::CheckMessageArgumentTypes(QualType ReceiverType,
+ Expr **Args, unsigned NumArgs,
Selector Sel, ObjCMethodDecl *Method,
- bool isClassMessage,
+ bool isClassMessage, bool isSuperMessage,
SourceLocation lbrac, SourceLocation rbrac,
QualType &ReturnType, ExprValueKind &VK) {
if (!Method) {
@@ -262,7 +330,8 @@ bool Sema::CheckMessageArgumentTypes(Expr **Args, unsigned NumArgs,
return false;
}
- ReturnType = Method->getSendResultType();
+ ReturnType = getMessageSendResultType(ReceiverType, Method, isClassMessage,
+ isSuperMessage);
VK = Expr::getValueKindForType(Method->getResultType());
unsigned NumNamedArgs = Sel.getNumArgs();
@@ -450,9 +519,12 @@ HandleExprPropertyRefExpr(const ObjCObjectPointerType *OPT,
ResTy = ResTy.getNonLValueExprType(Context);
Selector Sel = PP.getSelectorTable().getNullarySelector(Member);
ObjCMethodDecl *Getter = IFace->lookupInstanceMethod(Sel);
- if (DiagnosePropertyAccessorMismatch(PD, Getter, MemberLoc))
- ResTy = Getter->getResultType();
-
+ if (Getter &&
+ (Getter->hasRelatedResultType()
+ || DiagnosePropertyAccessorMismatch(PD, Getter, MemberLoc)))
+ ResTy = getMessageSendResultType(QualType(OPT, 0), Getter, false,
+ Super);
+
if (Super)
return Owned(new (Context) ObjCPropertyRefExpr(PD, ResTy,
VK_LValue, OK_ObjCProperty,
@@ -470,14 +542,18 @@ HandleExprPropertyRefExpr(const ObjCObjectPointerType *OPT,
// Check whether we can reference this property.
if (DiagnoseUseOfDecl(PD, MemberLoc))
return ExprError();
+
+ QualType T = PD->getType();
+ if (ObjCMethodDecl *Getter = PD->getGetterMethodDecl())
+ T = getMessageSendResultType(QualType(OPT, 0), Getter, false, Super);
if (Super)
- return Owned(new (Context) ObjCPropertyRefExpr(PD, PD->getType(),
+ return Owned(new (Context) ObjCPropertyRefExpr(PD, T,
VK_LValue,
OK_ObjCProperty,
MemberLoc,
SuperLoc, SuperType));
else
- return Owned(new (Context) ObjCPropertyRefExpr(PD, PD->getType(),
+ return Owned(new (Context) ObjCPropertyRefExpr(PD, T,
VK_LValue,
OK_ObjCProperty,
MemberLoc,
@@ -534,7 +610,7 @@ HandleExprPropertyRefExpr(const ObjCObjectPointerType *OPT,
if (Getter || Setter) {
QualType PType;
if (Getter)
- PType = Getter->getSendResultType();
+ PType = getMessageSendResultType(QualType(OPT, 0), Getter, false, Super);
else {
ParmVarDecl *ArgDecl = *Setter->param_begin();
PType = ArgDecl->getType();
@@ -608,10 +684,14 @@ ActOnClassPropertyRefExpr(IdentifierInfo &receiverName,
IdentifierInfo *receiverNamePtr = &receiverName;
ObjCInterfaceDecl *IFace = getObjCInterfaceDecl(receiverNamePtr,
receiverNameLoc);
+
+ bool IsSuper = false;
if (IFace == 0) {
// If the "receiver" is 'super' in a method, handle it as an expression-like
// property reference.
if (receiverNamePtr->isStr("super")) {
+ IsSuper = true;
+
if (ObjCMethodDecl *CurMethod = tryCaptureObjCSelf()) {
if (CurMethod->isInstanceMethod()) {
QualType T =
@@ -680,7 +760,9 @@ ActOnClassPropertyRefExpr(IdentifierInfo &receiverName,
ExprValueKind VK = VK_LValue;
if (Getter) {
- PType = Getter->getSendResultType();
+ PType = getMessageSendResultType(Context.getObjCInterfaceType(IFace),
+ Getter, true,
+ receiverNamePtr->isStr("super"));
if (!getLangOptions().CPlusPlus &&
!PType.hasQualifiers() && PType->isVoidType())
VK = VK_RValue;
@@ -693,6 +775,13 @@ ActOnClassPropertyRefExpr(IdentifierInfo &receiverName,
ExprObjectKind OK = (VK == VK_RValue ? OK_Ordinary : OK_ObjCProperty);
+ if (IsSuper)
+ return Owned(new (Context) ObjCPropertyRefExpr(Getter, Setter,
+ PType, VK, OK,
+ propertyNameLoc,
+ receiverNameLoc,
+ Context.getObjCInterfaceType(IFace)));
+
return Owned(new (Context) ObjCPropertyRefExpr(Getter, Setter,
PType, VK, OK,
propertyNameLoc,
@@ -949,8 +1038,9 @@ ExprResult Sema::BuildClassMessage(TypeSourceInfo *ReceiverTypeInfo,
unsigned NumArgs = ArgsIn.size();
Expr **Args = reinterpret_cast<Expr **>(ArgsIn.release());
- if (CheckMessageArgumentTypes(Args, NumArgs, Sel, Method, true,
- LBracLoc, RBracLoc, ReturnType, VK))
+ if (CheckMessageArgumentTypes(ReceiverType, Args, NumArgs, Sel, Method, true,
+ SuperLoc.isValid(), LBracLoc, RBracLoc,
+ ReturnType, VK))
return ExprError();
if (Method && !Method->getResultType()->isVoidType() &&
@@ -1232,7 +1322,8 @@ ExprResult Sema::BuildInstanceMessage(Expr *Receiver,
ExprValueKind VK = VK_RValue;
bool ClassMessage = (ReceiverType->isObjCClassType() ||
ReceiverType->isObjCQualifiedClassType());
- if (CheckMessageArgumentTypes(Args, NumArgs, Sel, Method, ClassMessage,
+ if (CheckMessageArgumentTypes(ReceiverType, Args, NumArgs, Sel, Method,
+ ClassMessage, SuperLoc.isValid(),
LBracLoc, RBracLoc, ReturnType, VK))
return ExprError();
diff --git a/lib/Sema/SemaInit.cpp b/lib/Sema/SemaInit.cpp
index ca3fd6d..a33f5d0 100644
--- a/lib/Sema/SemaInit.cpp
+++ b/lib/Sema/SemaInit.cpp
@@ -296,8 +296,7 @@ void InitListChecker::FillInValueInitForField(unsigned Init, FieldDecl *Field,
// Do nothing
} else if (Init < NumInits) {
ILE->setInit(Init, MemberInit.takeAs<Expr>());
- } else if (InitSeq.getKind()
- == InitializationSequence::ConstructorInitialization) {
+ } else if (InitSeq.isConstructorInitialization()) {
// Value-initialization requires a constructor call, so
// extend the initializer list to include the constructor
// call and make a note that we'll need to take another pass
@@ -418,8 +417,7 @@ InitListChecker::FillInValueInitializations(const InitializedEntity &Entity,
return;
}
- if (InitSeq.getKind()
- == InitializationSequence::ConstructorInitialization) {
+ if (InitSeq.isConstructorInitialization()) {
// Value-initialization requires a constructor call, so
// extend the initializer list to include the constructor
// call and make a note that we'll need to take another pass
@@ -2137,7 +2135,7 @@ bool InitializationSequence::isDirectReferenceBinding() const {
}
bool InitializationSequence::isAmbiguous() const {
- if (getKind() != FailedSequence)
+ if (!Failed())
return false;
switch (getFailureKind()) {
@@ -2310,7 +2308,7 @@ void InitializationSequence::AddArrayInitStep(QualType T) {
void InitializationSequence::SetOverloadFailure(FailureKind Failure,
OverloadingResult Result) {
- SequenceKind = FailedSequence;
+ setSequenceKind(FailedSequence);
this->Failure = Failure;
this->FailedOverloadResult = Result;
}
@@ -2331,7 +2329,6 @@ static void TryListInitialization(Sema &S,
// well-formed. When we actually "perform" list initialization, we'll
// do all of the necessary checking. C++0x initializer lists will
// force us to perform more checking here.
- Sequence.setSequenceKind(InitializationSequence::ListInitialization);
QualType DestType = Entity.getType();
@@ -2800,7 +2797,6 @@ static void TryStringLiteralInitialization(Sema &S,
const InitializationKind &Kind,
Expr *Initializer,
InitializationSequence &Sequence) {
- Sequence.setSequenceKind(InitializationSequence::StringInit);
Sequence.AddStringInitStep(Entity.getType());
}
@@ -2813,8 +2809,6 @@ static void TryConstructorInitialization(Sema &S,
Expr **Args, unsigned NumArgs,
QualType DestType,
InitializationSequence &Sequence) {
- Sequence.setSequenceKind(InitializationSequence::ConstructorInitialization);
-
// Build the candidate set directly in the initialization sequence
// structure, so that it will persist if we fail.
OverloadCandidateSet &CandidateSet = Sequence.getFailedCandidateSet();
@@ -2947,7 +2941,6 @@ static void TryValueInitialization(Sema &S,
}
Sequence.AddZeroInitializationStep(Entity.getType());
- Sequence.setSequenceKind(InitializationSequence::ZeroInitialization);
}
/// \brief Attempt default initialization (C++ [dcl.init]p6).
@@ -2973,7 +2966,6 @@ static void TryDefaultInitialization(Sema &S,
}
// - otherwise, no initialization is performed.
- Sequence.setSequenceKind(InitializationSequence::NoInitialization);
// If a program calls for the default initialization of an object of
// a const-qualified type T, T shall be a class type with a user-provided
@@ -2990,8 +2982,6 @@ static void TryUserDefinedConversion(Sema &S,
const InitializationKind &Kind,
Expr *Initializer,
InitializationSequence &Sequence) {
- Sequence.setSequenceKind(InitializationSequence::UserDefinedConversion);
-
QualType DestType = Entity.getType();
assert(!DestType->isReferenceType() && "References are handled elsewhere");
QualType SourceType = Initializer->getType();
@@ -3176,6 +3166,9 @@ InitializationSequence::InitializationSequence(Sema &S,
return;
}
+ // Almost everything is a normal sequence.
+ setSequenceKind(NormalSequence);
+
for (unsigned I = 0; I != NumArgs; ++I)
if (Args[I]->getObjectKind() == OK_ObjCProperty) {
ExprResult Result = S.ConvertPropertyForRValue(Args[I]);
@@ -3252,7 +3245,6 @@ InitializationSequence::InitializationSequence(Sema &S,
else if (Initializer->HasSideEffects(S.Context))
SetFailed(FK_NonConstantArrayInit);
else {
- setSequenceKind(ArrayInit);
AddArrayInitStep(DestType);
}
} else if (DestAT->getElementType()->isAnyCharacterType())
@@ -3265,7 +3257,6 @@ InitializationSequence::InitializationSequence(Sema &S,
// Handle initialization in C
if (!S.getLangOptions().CPlusPlus) {
- setSequenceKind(CAssignment);
AddCAssignmentStep(DestType);
return;
}
@@ -3325,8 +3316,6 @@ InitializationSequence::InitializationSequence(Sema &S,
else
SetFailed(InitializationSequence::FK_ConversionFailed);
}
- else
- setSequenceKind(StandardConversion);
}
InitializationSequence::~InitializationSequence() {
@@ -3650,13 +3639,13 @@ InitializationSequence::Perform(Sema &S,
const InitializationKind &Kind,
MultiExprArg Args,
QualType *ResultType) {
- if (SequenceKind == FailedSequence) {
+ if (Failed()) {
unsigned NumArgs = Args.size();
Diagnose(S, Entity, Kind, (Expr **)Args.release(), NumArgs);
return ExprError();
}
- if (SequenceKind == DependentSequence) {
+ if (getKind() == DependentSequence) {
// If the declaration is a non-dependent, incomplete array type
// that has an initializer, then its type will be completed once
// the initializer is instantiated.
@@ -3710,7 +3699,8 @@ InitializationSequence::Perform(Sema &S,
SourceLocation()));
}
- if (SequenceKind == NoInitialization)
+ // No steps means no initialization.
+ if (Steps.empty())
return S.Owned((Expr *)0);
QualType DestType = Entity.getType().getNonReferenceType();
@@ -3723,8 +3713,6 @@ InitializationSequence::Perform(Sema &S,
ExprResult CurInit = S.Owned((Expr *)0);
- assert(!Steps.empty() && "Cannot have an empty initialization sequence");
-
// For initialization steps that start with a single initializer,
// grab the only argument out the Args and place it into the "current"
// initializer.
@@ -4019,8 +4007,9 @@ InitializationSequence::Perform(Sema &S,
// the definition for completely trivial constructors.
CXXRecordDecl *ClassDecl = Constructor->getParent();
assert(ClassDecl && "No parent class for constructor.");
- if (Constructor->isImplicit() && Constructor->isDefaultConstructor() &&
- ClassDecl->hasTrivialConstructor() && !Constructor->isUsed(false))
+ if (Constructor->isDefaulted() && Constructor->isDefaultConstructor() &&
+ ClassDecl->hasTrivialDefaultConstructor() &&
+ !Constructor->isUsed(false))
S.DefineImplicitDefaultConstructor(Loc, Constructor);
}
@@ -4060,8 +4049,7 @@ InitializationSequence::Perform(Sema &S,
ConstructKind = Entity.getBaseSpecifier()->isVirtual() ?
CXXConstructExpr::CK_VirtualBase :
CXXConstructExpr::CK_NonVirtualBase;
- }
- if (Entity.getKind() == InitializedEntity::EK_Delegating) {
+ } else if (Entity.getKind() == InitializedEntity::EK_Delegating) {
ConstructKind = CXXConstructExpr::CK_Delegating;
}
@@ -4216,7 +4204,7 @@ bool InitializationSequence::Diagnose(Sema &S,
const InitializedEntity &Entity,
const InitializationKind &Kind,
Expr **Args, unsigned NumArgs) {
- if (SequenceKind != FailedSequence)
+ if (!Failed())
return false;
QualType DestType = Entity.getType();
@@ -4334,6 +4322,9 @@ bool InitializationSequence::Diagnose(Sema &S,
<< Args[0]->isLValue()
<< Args[0]->getType()
<< Args[0]->getSourceRange();
+ if (DestType.getNonReferenceType()->isObjCObjectPointerType() &&
+ Args[0]->getType()->isObjCObjectPointerType())
+ S.EmitRelatedResultTypeNote(Args[0]);
break;
case FK_ConversionFailed: {
@@ -4344,6 +4335,9 @@ bool InitializationSequence::Diagnose(Sema &S,
<< Args[0]->isLValue()
<< FromType
<< Args[0]->getSourceRange();
+ if (DestType.getNonReferenceType()->isObjCObjectPointerType() &&
+ Args[0]->getType()->isObjCObjectPointerType())
+ S.EmitRelatedResultTypeNote(Args[0]);
break;
}
@@ -4587,48 +4581,16 @@ void InitializationSequence::dump(llvm::raw_ostream &OS) const {
}
case DependentSequence:
- OS << "Dependent sequence: ";
+ OS << "Dependent sequence\n";
return;
- case UserDefinedConversion:
- OS << "User-defined conversion sequence: ";
- break;
-
- case ConstructorInitialization:
- OS << "Constructor initialization sequence: ";
+ case NormalSequence:
+ OS << "Normal sequence: ";
break;
case ReferenceBinding:
OS << "Reference binding: ";
break;
-
- case ListInitialization:
- OS << "List initialization: ";
- break;
-
- case ZeroInitialization:
- OS << "Zero initialization\n";
- return;
-
- case NoInitialization:
- OS << "No initialization\n";
- return;
-
- case StandardConversion:
- OS << "Standard conversion: ";
- break;
-
- case CAssignment:
- OS << "C assignment: ";
- break;
-
- case StringInit:
- OS << "String initialization: ";
- break;
-
- case ArrayInit:
- OS << "Array initialization: ";
- break;
}
for (step_iterator S = step_begin(), SEnd = step_end(); S != SEnd; ++S) {
@@ -4723,6 +4685,21 @@ void InitializationSequence::dump() const {
//===----------------------------------------------------------------------===//
// Initialization helper functions
//===----------------------------------------------------------------------===//
+bool
+Sema::CanPerformCopyInitialization(const InitializedEntity &Entity,
+ ExprResult Init) {
+ if (Init.isInvalid())
+ return false;
+
+ Expr *InitE = Init.get();
+ assert(InitE && "No initialization expression");
+
+ InitializationKind Kind = InitializationKind::CreateCopy(SourceLocation(),
+ SourceLocation());
+ InitializationSequence Seq(*this, Entity, Kind, &InitE, 1);
+ return !Seq.Failed();
+}
+
ExprResult
Sema::PerformCopyInitialization(const InitializedEntity &Entity,
SourceLocation EqualLoc,
diff --git a/lib/Sema/SemaLookup.cpp b/lib/Sema/SemaLookup.cpp
index 309c771..92ade1e 100644
--- a/lib/Sema/SemaLookup.cpp
+++ b/lib/Sema/SemaLookup.cpp
@@ -14,6 +14,7 @@
#include "clang/Sema/Sema.h"
#include "clang/Sema/SemaInternal.h"
#include "clang/Sema/Lookup.h"
+#include "clang/Sema/Overload.h"
#include "clang/Sema/DeclSpec.h"
#include "clang/Sema/Scope.h"
#include "clang/Sema/ScopeInfo.h"
@@ -534,7 +535,7 @@ void Sema::ForceDeclarationOfImplicitMembers(CXXRecordDecl *Class) {
return;
// If the default constructor has not yet been declared, do so now.
- if (!Class->hasDeclaredDefaultConstructor())
+ if (Class->needsImplicitDefaultConstructor())
DeclareImplicitDefaultConstructor(Class);
// If the copy constructor has not yet been declared, do so now.
@@ -581,7 +582,7 @@ static void DeclareImplicitMemberFunctionsWithName(Sema &S,
if (const CXXRecordDecl *Record = dyn_cast<CXXRecordDecl>(DC))
if (Record->getDefinition() &&
CanDeclareSpecialMemberFunction(S.Context, Record)) {
- if (!Record->hasDeclaredDefaultConstructor())
+ if (Record->needsImplicitDefaultConstructor())
S.DeclareImplicitDefaultConstructor(
const_cast<CXXRecordDecl *>(Record));
if (!Record->hasDeclaredCopyConstructor())
@@ -2136,11 +2137,200 @@ void Sema::LookupOverloadedOperatorName(OverloadedOperatorKind Op, Scope *S,
}
}
+Sema::SpecialMemberOverloadResult *Sema::LookupSpecialMember(CXXRecordDecl *D,
+ CXXSpecialMember SM,
+ bool ConstArg,
+ bool VolatileArg,
+ bool RValueThis,
+ bool ConstThis,
+ bool VolatileThis) {
+ D = D->getDefinition();
+ assert((D && !D->isBeingDefined()) &&
+ "doing special member lookup into record that isn't fully complete");
+ if (RValueThis || ConstThis || VolatileThis)
+ assert((SM == CXXCopyAssignment || SM == CXXMoveAssignment) &&
+ "constructors and destructors always have unqualified lvalue this");
+ if (ConstArg || VolatileArg)
+ assert((SM != CXXDefaultConstructor && SM != CXXDestructor) &&
+ "parameter-less special members can't have qualified arguments");
+
+ llvm::FoldingSetNodeID ID;
+ ID.AddPointer(D);
+ ID.AddInteger(SM);
+ ID.AddInteger(ConstArg);
+ ID.AddInteger(VolatileArg);
+ ID.AddInteger(RValueThis);
+ ID.AddInteger(ConstThis);
+ ID.AddInteger(VolatileThis);
+
+ void *InsertPoint;
+ SpecialMemberOverloadResult *Result =
+ SpecialMemberCache.FindNodeOrInsertPos(ID, InsertPoint);
+
+ // This was already cached
+ if (Result)
+ return Result;
+
+ Result = BumpAlloc.Allocate<SpecialMemberOverloadResult>();
+ Result = new (Result) SpecialMemberOverloadResult(ID);
+ SpecialMemberCache.InsertNode(Result, InsertPoint);
+
+ if (SM == CXXDestructor) {
+ if (!D->hasDeclaredDestructor())
+ DeclareImplicitDestructor(D);
+ CXXDestructorDecl *DD = D->getDestructor();
+ assert(DD && "record without a destructor");
+ Result->setMethod(DD);
+ Result->setSuccess(DD->isDeleted());
+ Result->setConstParamMatch(false);
+ return Result;
+ }
+
+ // Prepare for overload resolution. Here we construct a synthetic argument
+ // if necessary and make sure that implicit functions are declared.
+ CanQualType CanTy = Context.getCanonicalType(Context.getTagDeclType(D));
+ DeclarationName Name;
+ Expr *Arg = 0;
+ unsigned NumArgs;
+
+ if (SM == CXXDefaultConstructor) {
+ Name = Context.DeclarationNames.getCXXConstructorName(CanTy);
+ NumArgs = 0;
+ if (D->needsImplicitDefaultConstructor())
+ DeclareImplicitDefaultConstructor(D);
+ } else {
+ if (SM == CXXCopyConstructor || SM == CXXMoveConstructor) {
+ Name = Context.DeclarationNames.getCXXConstructorName(CanTy);
+ if (!D->hasDeclaredCopyConstructor())
+ DeclareImplicitCopyConstructor(D);
+ // TODO: Move constructors
+ } else {
+ Name = Context.DeclarationNames.getCXXOperatorName(OO_Equal);
+ if (!D->hasDeclaredCopyAssignment())
+ DeclareImplicitCopyAssignment(D);
+ // TODO: Move assignment
+ }
+
+ QualType ArgType = CanTy;
+ if (ConstArg)
+ ArgType.addConst();
+ if (VolatileArg)
+ ArgType.addVolatile();
+
+ // This isn't /really/ specified by the standard, but it's implied
+ // we should be working from an RValue in the case of move to ensure
+ // that we prefer to bind to rvalue references, and an LValue in the
+ // case of copy to ensure we don't bind to rvalue references.
+ // Possibly an XValue is actually correct in the case of move, but
+ // there is no semantic difference for class types in this restricted
+ // case.
+ ExprValueKind VK;
+ if (SM == CXXCopyAssignment || SM == CXXMoveAssignment)
+ VK = VK_LValue;
+ else
+ VK = VK_RValue;
+
+ NumArgs = 1;
+ Arg = new (Context) OpaqueValueExpr(SourceLocation(), ArgType, VK);
+ }
+
+ // Create the object argument
+ QualType ThisTy = CanTy;
+ if (ConstThis)
+ ThisTy.addConst();
+ if (VolatileThis)
+ ThisTy.addVolatile();
+ Expr::Classification ObjectClassification =
+ (new (Context) OpaqueValueExpr(SourceLocation(), ThisTy,
+ RValueThis ? VK_RValue : VK_LValue))->
+ Classify(Context);
+
+ // Now we perform lookup on the name we computed earlier and do overload
+ // resolution. Lookup is only performed directly into the class since there
+ // will always be a (possibly implicit) declaration to shadow any others.
+ OverloadCandidateSet OCS((SourceLocation()));
+ DeclContext::lookup_iterator I, E;
+ Result->setConstParamMatch(false);
+
+ llvm::tie(I, E) = D->lookup(Name);
+ assert((I != E) &&
+ "lookup for a constructor or assignment operator was empty");
+ for ( ; I != E; ++I) {
+ if ((*I)->isInvalidDecl())
+ continue;
+
+ if (CXXMethodDecl *M = dyn_cast<CXXMethodDecl>(*I)) {
+ AddOverloadCandidate(M, DeclAccessPair::make(M, AS_public), &Arg, NumArgs,
+ OCS, true);
+
+ // Here we're looking for a const parameter to speed up creation of
+ // implicit copy methods.
+ if ((SM == CXXCopyAssignment && M->isCopyAssignmentOperator()) ||
+ (SM == CXXCopyConstructor &&
+ cast<CXXConstructorDecl>(M)->isCopyConstructor())) {
+ QualType ArgType = M->getType()->getAs<FunctionProtoType>()->getArgType(0);
+ if (ArgType->getPointeeType().isConstQualified())
+ Result->setConstParamMatch(true);
+ }
+ } else {
+ FunctionTemplateDecl *Tmpl = cast<FunctionTemplateDecl>(*I);
+ AddTemplateOverloadCandidate(Tmpl, DeclAccessPair::make(Tmpl, AS_public),
+ 0, &Arg, NumArgs, OCS, true);
+ }
+ }
+
+ OverloadCandidateSet::iterator Best;
+ switch (OCS.BestViableFunction(*this, SourceLocation(), Best)) {
+ case OR_Success:
+ Result->setMethod(cast<CXXMethodDecl>(Best->Function));
+ Result->setSuccess(true);
+ break;
+
+ case OR_Deleted:
+ Result->setMethod(cast<CXXMethodDecl>(Best->Function));
+ Result->setSuccess(false);
+ break;
+
+ case OR_Ambiguous:
+ case OR_No_Viable_Function:
+ Result->setMethod(0);
+ Result->setSuccess(false);
+ break;
+ }
+
+ return Result;
+}
+
+/// \brief Look up the default constructor for the given class.
+CXXConstructorDecl *Sema::LookupDefaultConstructor(CXXRecordDecl *Class) {
+ SpecialMemberOverloadResult *Result =
+ LookupSpecialMember(Class, CXXDefaultConstructor, false, false, false,
+ false, false);
+
+ return cast_or_null<CXXConstructorDecl>(Result->getMethod());
+}
+
+/// \brief Look up the copy constructor for the given class.
+CXXConstructorDecl *Sema::LookupCopyConstructor(CXXRecordDecl *Class,
+ unsigned Quals,
+ bool *ConstParamMatch) {
+ assert(!(Quals & ~(Qualifiers::Const | Qualifiers::Volatile)) &&
+ "non-const, non-volatile qualifiers for copy ctor arg");
+ SpecialMemberOverloadResult *Result =
+ LookupSpecialMember(Class, CXXCopyConstructor, Quals & Qualifiers::Const,
+ Quals & Qualifiers::Volatile, false, false, false);
+
+ if (ConstParamMatch)
+ *ConstParamMatch = Result->hasConstParamMatch();
+
+ return cast_or_null<CXXConstructorDecl>(Result->getMethod());
+}
+
/// \brief Look up the constructors for the given class.
DeclContext::lookup_result Sema::LookupConstructors(CXXRecordDecl *Class) {
- // If the copy constructor has not yet been declared, do so now.
+ // If the implicit constructors have not yet been declared, do so now.
if (CanDeclareSpecialMemberFunction(Context, Class)) {
- if (!Class->hasDeclaredDefaultConstructor())
+ if (Class->needsImplicitDefaultConstructor())
DeclareImplicitDefaultConstructor(Class);
if (!Class->hasDeclaredCopyConstructor())
DeclareImplicitCopyConstructor(Class);
@@ -2158,12 +2348,9 @@ DeclContext::lookup_result Sema::LookupConstructors(CXXRecordDecl *Class) {
///
/// \returns The destructor for this class.
CXXDestructorDecl *Sema::LookupDestructor(CXXRecordDecl *Class) {
- // If the destructor has not yet been declared, do so now.
- if (CanDeclareSpecialMemberFunction(Context, Class) &&
- !Class->hasDeclaredDestructor())
- DeclareImplicitDestructor(Class);
-
- return Class->getDestructor();
+ return cast<CXXDestructorDecl>(LookupSpecialMember(Class, CXXDestructor,
+ false, false, false,
+ false, false)->getMethod());
}
void ADLResult::insert(NamedDecl *New) {
@@ -2410,8 +2597,8 @@ VisibleDeclsRecord::ShadowMapEntry::end() {
if (DeclOrVector.isNull())
return 0;
- if (DeclOrVector.dyn_cast<NamedDecl *>())
- return &reinterpret_cast<NamedDecl*&>(DeclOrVector) + 1;
+ if (DeclOrVector.is<NamedDecl *>())
+ return DeclOrVector.getAddrOf<NamedDecl *>() + 1;
return DeclOrVector.get<DeclVector *>()->end();
}
diff --git a/lib/Sema/SemaOverload.cpp b/lib/Sema/SemaOverload.cpp
index 3f3ed0e..4bba6f8 100644
--- a/lib/Sema/SemaOverload.cpp
+++ b/lib/Sema/SemaOverload.cpp
@@ -1628,6 +1628,15 @@ bool Sema::IsPointerConversion(Expr *From, QualType FromType, QualType ToType,
return true;
}
+ // MSVC allows implicit function to void* type conversion.
+ if (getLangOptions().Microsoft && FromPointeeType->isFunctionType() &&
+ ToPointeeType->isVoidType()) {
+ ConvertedType = BuildSimilarlyQualifiedPointerType(FromTypePtr,
+ ToPointeeType,
+ ToType, Context);
+ return true;
+ }
+
// When we're overloading in C, we allow a special kind of pointer
// conversion for compatible-but-not-identical pointee types.
if (!getLangOptions().CPlusPlus &&
@@ -2197,6 +2206,13 @@ Sema::IsQualificationConversion(QualType FromType, QualType ToType,
Qualifiers FromQuals = FromType.getQualifiers();
Qualifiers ToQuals = ToType.getQualifiers();
+ // Allow addition/removal of GC attributes but not changing GC attributes.
+ if (FromQuals.getObjCGCAttr() != ToQuals.getObjCGCAttr() &&
+ (!FromQuals.hasObjCGCAttr() || !ToQuals.hasObjCGCAttr())) {
+ FromQuals.removeObjCGCAttr();
+ ToQuals.removeObjCGCAttr();
+ }
+
// -- for every j > 0, if const is in cv 1,j then const is in cv
// 2,j, and similarly for volatile.
if (!CStyle && !ToQuals.compatiblyIncludes(FromQuals))
@@ -2507,12 +2523,10 @@ compareStandardConversionSubsets(ASTContext &Context,
// 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.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)
@@ -4689,6 +4703,10 @@ class BuiltinCandidateTypeSet {
/// were present in the candidate set.
bool HasArithmeticOrEnumeralTypes;
+ /// \brief A flag indicating whether the nullptr type was present in the
+ /// candidate set.
+ bool HasNullPtrType;
+
/// Sema - The semantic analysis instance where we are building the
/// candidate type set.
Sema &SemaRef;
@@ -4707,6 +4725,7 @@ public:
BuiltinCandidateTypeSet(Sema &SemaRef)
: HasNonRecordTypes(false),
HasArithmeticOrEnumeralTypes(false),
+ HasNullPtrType(false),
SemaRef(SemaRef),
Context(SemaRef.Context) { }
@@ -4739,6 +4758,7 @@ public:
bool hasNonRecordTypes() { return HasNonRecordTypes; }
bool hasArithmeticOrEnumeralTypes() { return HasArithmeticOrEnumeralTypes; }
+ bool hasNullPtrType() const { return HasNullPtrType; }
};
/// AddPointerWithMoreQualifiedTypeVariants - Add the pointer type @p Ty to
@@ -4899,6 +4919,8 @@ BuiltinCandidateTypeSet::AddTypesConvertedFrom(QualType Ty,
// extension.
HasArithmeticOrEnumeralTypes = true;
VectorTypes.insert(Ty);
+ } else if (Ty->isNullPtrType()) {
+ HasNullPtrType = true;
} else if (AllowUserConversions && TyRec) {
// No conversion functions in incomplete types.
if (SemaRef.RequireCompleteType(Loc, Ty, 0))
@@ -5358,8 +5380,8 @@ public:
// C++ [over.built]p15:
//
- // For every pointer or enumeration type T, there exist
- // candidate operator functions of the form
+ // For every T, where T is an enumeration type, a pointer type, or
+ // std::nullptr_t, there exist candidate operator functions of the form
//
// bool operator<(T, T);
// bool operator>(T, T);
@@ -5444,6 +5466,17 @@ public:
S.AddBuiltinCandidate(S.Context.BoolTy, ParamTypes, Args, 2,
CandidateSet);
}
+
+ if (CandidateTypes[ArgIdx].hasNullPtrType()) {
+ CanQualType NullPtrTy = S.Context.getCanonicalType(S.Context.NullPtrTy);
+ if (AddedTypes.insert(NullPtrTy) &&
+ !UserDefinedBinaryOperators.count(std::make_pair(NullPtrTy,
+ NullPtrTy))) {
+ QualType ParamTypes[2] = { NullPtrTy, NullPtrTy };
+ S.AddBuiltinCandidate(S.Context.BoolTy, ParamTypes, Args, 2,
+ CandidateSet);
+ }
+ }
}
}
@@ -6401,7 +6434,9 @@ enum OverloadCandidateKind {
oc_constructor_template,
oc_implicit_default_constructor,
oc_implicit_copy_constructor,
+ oc_implicit_move_constructor,
oc_implicit_copy_assignment,
+ oc_implicit_move_assignment,
oc_implicit_inherited_constructor
};
@@ -6423,8 +6458,15 @@ OverloadCandidateKind ClassifyOverloadCandidate(Sema &S,
if (Ctor->getInheritedConstructor())
return oc_implicit_inherited_constructor;
- return Ctor->isCopyConstructor() ? oc_implicit_copy_constructor
- : oc_implicit_default_constructor;
+ if (Ctor->isDefaultConstructor())
+ return oc_implicit_default_constructor;
+
+ if (Ctor->isMoveConstructor())
+ return oc_implicit_move_constructor;
+
+ assert(Ctor->isCopyConstructor() &&
+ "unexpected sort of implicit constructor");
+ return oc_implicit_copy_constructor;
}
if (CXXMethodDecl *Meth = dyn_cast<CXXMethodDecl>(Fn)) {
@@ -6433,6 +6475,9 @@ OverloadCandidateKind ClassifyOverloadCandidate(Sema &S,
if (!Meth->isImplicit())
return isTemplate ? oc_method_template : oc_method;
+ if (Meth->isMoveAssignmentOperator())
+ return oc_implicit_move_assignment;
+
assert(Meth->isCopyAssignmentOperator()
&& "implicit method is not copy assignment operator?");
return oc_implicit_copy_assignment;
@@ -6676,6 +6721,15 @@ void DiagnoseArityMismatch(Sema &S, OverloadCandidate *Cand,
unsigned MinParams = Fn->getMinRequiredArguments();
+ // With invalid overloaded operators, it's possible that we think we
+ // have an arity mismatch when it fact it looks like we have the
+ // right number of arguments, because only overloaded operators have
+ // the weird behavior of overloading member and non-member functions.
+ // Just don't report anything.
+ if (Fn->isInvalidDecl() &&
+ Fn->getDeclName().getNameKind() == DeclarationName::CXXOperatorName)
+ return;
+
// at least / at most / exactly
unsigned mode, modeCount;
if (NumFormalArgs < MinParams) {
@@ -7772,6 +7826,111 @@ void Sema::AddOverloadedCallCandidates(UnresolvedLookupExpr *ULE,
ULE->isStdAssociatedNamespace());
}
+/// Attempt to recover from an ill-formed use of a non-dependent name in a
+/// template, where the non-dependent name was declared after the template
+/// was defined. This is common in code written for a compilers which do not
+/// correctly implement two-stage name lookup.
+///
+/// Returns true if a viable candidate was found and a diagnostic was issued.
+static bool
+DiagnoseTwoPhaseLookup(Sema &SemaRef, SourceLocation FnLoc,
+ const CXXScopeSpec &SS, LookupResult &R,
+ TemplateArgumentListInfo *ExplicitTemplateArgs,
+ Expr **Args, unsigned NumArgs) {
+ if (SemaRef.ActiveTemplateInstantiations.empty() || !SS.isEmpty())
+ return false;
+
+ for (DeclContext *DC = SemaRef.CurContext; DC; DC = DC->getParent()) {
+ SemaRef.LookupQualifiedName(R, DC);
+
+ if (!R.empty()) {
+ R.suppressDiagnostics();
+
+ if (isa<CXXRecordDecl>(DC)) {
+ // Don't diagnose names we find in classes; we get much better
+ // diagnostics for these from DiagnoseEmptyLookup.
+ R.clear();
+ return false;
+ }
+
+ OverloadCandidateSet Candidates(FnLoc);
+ for (LookupResult::iterator I = R.begin(), E = R.end(); I != E; ++I)
+ AddOverloadedCallCandidate(SemaRef, I.getPair(),
+ ExplicitTemplateArgs, Args, NumArgs,
+ Candidates, false);
+
+ OverloadCandidateSet::iterator Best;
+ if (Candidates.BestViableFunction(SemaRef, FnLoc, Best) != OR_Success)
+ // No viable functions. Don't bother the user with notes for functions
+ // which don't work and shouldn't be found anyway.
+ return false;
+
+ // Find the namespaces where ADL would have looked, and suggest
+ // declaring the function there instead.
+ Sema::AssociatedNamespaceSet AssociatedNamespaces;
+ Sema::AssociatedClassSet AssociatedClasses;
+ SemaRef.FindAssociatedClassesAndNamespaces(Args, NumArgs,
+ AssociatedNamespaces,
+ AssociatedClasses);
+ // Never suggest declaring a function within namespace 'std'.
+ Sema::AssociatedNamespaceSet SuggestedNamespaces;
+ if (DeclContext *Std = SemaRef.getStdNamespace()) {
+ for (Sema::AssociatedNamespaceSet::iterator
+ it = AssociatedNamespaces.begin(),
+ end = AssociatedNamespaces.end(); it != end; ++it) {
+ if (!Std->Encloses(*it))
+ SuggestedNamespaces.insert(*it);
+ }
+ } else {
+ // Lacking the 'std::' namespace, use all of the associated namespaces.
+ SuggestedNamespaces = AssociatedNamespaces;
+ }
+
+ SemaRef.Diag(R.getNameLoc(), diag::err_not_found_by_two_phase_lookup)
+ << R.getLookupName();
+ if (SuggestedNamespaces.empty()) {
+ SemaRef.Diag(Best->Function->getLocation(),
+ diag::note_not_found_by_two_phase_lookup)
+ << R.getLookupName() << 0;
+ } else if (SuggestedNamespaces.size() == 1) {
+ SemaRef.Diag(Best->Function->getLocation(),
+ diag::note_not_found_by_two_phase_lookup)
+ << R.getLookupName() << 1 << *SuggestedNamespaces.begin();
+ } else {
+ // FIXME: It would be useful to list the associated namespaces here,
+ // but the diagnostics infrastructure doesn't provide a way to produce
+ // a localized representation of a list of items.
+ SemaRef.Diag(Best->Function->getLocation(),
+ diag::note_not_found_by_two_phase_lookup)
+ << R.getLookupName() << 2;
+ }
+
+ // Try to recover by calling this function.
+ return true;
+ }
+
+ R.clear();
+ }
+
+ return false;
+}
+
+/// Attempt to recover from ill-formed use of a non-dependent operator in a
+/// template, where the non-dependent operator was declared after the template
+/// was defined.
+///
+/// Returns true if a viable candidate was found and a diagnostic was issued.
+static bool
+DiagnoseTwoPhaseOperatorLookup(Sema &SemaRef, OverloadedOperatorKind Op,
+ SourceLocation OpLoc,
+ Expr **Args, unsigned NumArgs) {
+ DeclarationName OpName =
+ SemaRef.Context.DeclarationNames.getCXXOperatorName(Op);
+ LookupResult R(SemaRef, OpName, OpLoc, Sema::LookupOperatorName);
+ return DiagnoseTwoPhaseLookup(SemaRef, OpLoc, CXXScopeSpec(), R,
+ /*ExplicitTemplateArgs=*/0, Args, NumArgs);
+}
+
/// Attempts to recover from a call where no functions were found.
///
/// Returns true if new candidates were found.
@@ -7780,13 +7939,14 @@ BuildRecoveryCallExpr(Sema &SemaRef, Scope *S, Expr *Fn,
UnresolvedLookupExpr *ULE,
SourceLocation LParenLoc,
Expr **Args, unsigned NumArgs,
- SourceLocation RParenLoc) {
+ SourceLocation RParenLoc,
+ bool EmptyLookup) {
CXXScopeSpec SS;
SS.Adopt(ULE->getQualifierLoc());
TemplateArgumentListInfo TABuffer;
- const TemplateArgumentListInfo *ExplicitTemplateArgs = 0;
+ TemplateArgumentListInfo *ExplicitTemplateArgs = 0;
if (ULE->hasExplicitTemplateArgs()) {
ULE->copyTemplateArgumentsInto(TABuffer);
ExplicitTemplateArgs = &TABuffer;
@@ -7794,7 +7954,10 @@ BuildRecoveryCallExpr(Sema &SemaRef, Scope *S, Expr *Fn,
LookupResult R(SemaRef, ULE->getName(), ULE->getNameLoc(),
Sema::LookupOrdinaryName);
- if (SemaRef.DiagnoseEmptyLookup(S, SS, R, Sema::CTC_Expression))
+ if (!DiagnoseTwoPhaseLookup(SemaRef, Fn->getExprLoc(), SS, R,
+ ExplicitTemplateArgs, Args, NumArgs) &&
+ (!EmptyLookup ||
+ SemaRef.DiagnoseEmptyLookup(S, SS, R, Sema::CTC_Expression)))
return ExprError();
assert(!R.empty() && "lookup results empty despite recovery");
@@ -7814,7 +7977,7 @@ BuildRecoveryCallExpr(Sema &SemaRef, Scope *S, Expr *Fn,
return ExprError();
// This shouldn't cause an infinite loop because we're giving it
- // an expression with non-empty lookup results, which should never
+ // an expression with viable lookup results, which should never
// end up here.
return SemaRef.ActOnCallExpr(/*Scope*/ 0, NewFn.take(), LParenLoc,
MultiExprArg(Args, NumArgs), RParenLoc);
@@ -7860,11 +8023,11 @@ Sema::BuildOverloadedCallExpr(Scope *S, Expr *Fn, UnresolvedLookupExpr *ULE,
AddOverloadedCallCandidates(ULE, Args, NumArgs, CandidateSet);
// If we found nothing, try to recover.
- // AddRecoveryCallCandidates diagnoses the error itself, so we just
- // bailout out if it fails.
+ // BuildRecoveryCallExpr diagnoses the error itself, so we just bail
+ // out if it fails.
if (CandidateSet.empty())
return BuildRecoveryCallExpr(*this, S, Fn, ULE, LParenLoc, Args, NumArgs,
- RParenLoc);
+ RParenLoc, /*EmptyLookup=*/true);
OverloadCandidateSet::iterator Best;
switch (CandidateSet.BestViableFunction(*this, Fn->getLocStart(), Best)) {
@@ -7879,12 +8042,21 @@ Sema::BuildOverloadedCallExpr(Scope *S, Expr *Fn, UnresolvedLookupExpr *ULE,
ExecConfig);
}
- case OR_No_Viable_Function:
+ case OR_No_Viable_Function: {
+ // Try to recover by looking for viable functions which the user might
+ // have meant to call.
+ ExprResult Recovery = BuildRecoveryCallExpr(*this, S, Fn, ULE, LParenLoc,
+ Args, NumArgs, RParenLoc,
+ /*EmptyLookup=*/false);
+ if (!Recovery.isInvalid())
+ return Recovery;
+
Diag(Fn->getSourceRange().getBegin(),
diag::err_ovl_no_viable_function_in_call)
<< ULE->getName() << Fn->getSourceRange();
CandidateSet.NoteCandidates(*this, OCD_AllCandidates, Args, NumArgs);
break;
+ }
case OR_Ambiguous:
Diag(Fn->getSourceRange().getBegin(), diag::err_ovl_ambiguous_call)
@@ -8073,6 +8245,13 @@ Sema::CreateOverloadedUnaryOp(SourceLocation OpLoc, unsigned OpcIn,
}
case OR_No_Viable_Function:
+ // This is an erroneous use of an operator which can be overloaded by
+ // a non-member function. Check for non-member operators which were
+ // defined too late to be candidates.
+ if (DiagnoseTwoPhaseOperatorLookup(*this, Op, OpLoc, Args, NumArgs))
+ // FIXME: Recover by calling the found function.
+ return ExprError();
+
// No viable function; fall through to handling this as a
// built-in operator, which will produce an error message for us.
break;
@@ -8354,6 +8533,13 @@ Sema::CreateOverloadedBinOp(SourceLocation OpLoc,
<< BinaryOperator::getOpcodeStr(Opc)
<< Args[0]->getSourceRange() << Args[1]->getSourceRange();
} else {
+ // This is an erroneous use of an operator which can be overloaded by
+ // a non-member function. Check for non-member operators which were
+ // defined too late to be candidates.
+ if (DiagnoseTwoPhaseOperatorLookup(*this, Op, OpLoc, Args, 2))
+ // FIXME: Recover by calling the found function.
+ return ExprError();
+
// No viable function; try to create a built-in operation, which will
// produce an error. Then, show the non-viable candidates.
Result = CreateBuiltinBinOp(OpLoc, Opc, Args[0], Args[1]);
@@ -8772,6 +8958,19 @@ Sema::BuildCallToMemberFunction(Scope *S, Expr *MemExprE,
if (CheckFunctionCall(Method, TheCall))
return ExprError();
+ if ((isa<CXXConstructorDecl>(CurContext) ||
+ isa<CXXDestructorDecl>(CurContext)) &&
+ TheCall->getMethodDecl()->isPure()) {
+ const CXXMethodDecl *MD = TheCall->getMethodDecl();
+
+ if (isa<CXXThisExpr>(MemExpr->getBase()->IgnoreParenCasts()))
+ Diag(MemExpr->getLocStart(),
+ diag::warn_call_to_pure_virtual_member_function_from_ctor_dtor)
+ << MD->getDeclName() << isa<CXXDestructorDecl>(CurContext)
+ << MD->getParent()->getDeclName();
+
+ Diag(MD->getLocStart(), diag::note_previous_decl) << MD->getDeclName();
+ }
return MaybeBindToTemporary(TheCall);
}
diff --git a/lib/Sema/SemaStmt.cpp b/lib/Sema/SemaStmt.cpp
index 65cea7a..d7c0a54 100644
--- a/lib/Sema/SemaStmt.cpp
+++ b/lib/Sema/SemaStmt.cpp
@@ -501,7 +501,8 @@ Sema::ActOnFinishSwitchStmt(SourceLocation SwitchLoc, Stmt *Switch,
= CondExpr->isTypeDependent() || CondExpr->isValueDependent();
unsigned CondWidth
= HasDependentValue ? 0 : Context.getIntWidth(CondTypeBeforePromotion);
- bool CondIsSigned = CondTypeBeforePromotion->isSignedIntegerType();
+ bool CondIsSigned
+ = CondTypeBeforePromotion->isSignedIntegerOrEnumerationType();
// Accumulate all of the case values in a vector so that we can sort them
// and detect duplicates. This vector contains the APInt for the case after
@@ -723,7 +724,8 @@ Sema::ActOnFinishSwitchStmt(SourceLocation SwitchLoc, Stmt *Switch,
// If switch has default case, then ignore it.
if (!CaseListIsErroneous && !HasConstantCond && ET) {
const EnumDecl *ED = ET->getDecl();
- typedef llvm::SmallVector<std::pair<llvm::APSInt, EnumConstantDecl*>, 64> EnumValsTy;
+ typedef llvm::SmallVector<std::pair<llvm::APSInt, EnumConstantDecl*>, 64>
+ EnumValsTy;
EnumValsTy EnumVals;
// Gather all enum values, set their type and sort them,
@@ -1252,7 +1254,8 @@ Sema::BuildCXXForRangeStmt(SourceLocation ForLoc, SourceLocation ColonLoc,
ExprResult BoundExpr;
if (const ConstantArrayType *CAT = dyn_cast<ConstantArrayType>(UnqAT))
BoundExpr = Owned(IntegerLiteral::Create(Context, CAT->getSize(),
- Context.IntTy, RangeLoc));
+ Context.getPointerDiffType(),
+ RangeLoc));
else if (const VariableArrayType *VAT =
dyn_cast<VariableArrayType>(UnqAT))
BoundExpr = VAT->getSizeExpr();
@@ -1455,7 +1458,10 @@ Sema::ActOnBreakStmt(SourceLocation BreakLoc, Scope *CurScope) {
/// \param E The expression being returned from the function or block, or
/// being thrown.
///
-/// \param AllowFunctionParameter
+/// \param AllowFunctionParameter Whether we allow function parameters to
+/// be considered NRVO candidates. C++ prohibits this for NRVO itself, but
+/// we re-use this logic to determine whether we should try to move as part of
+/// a return or throw (which does allow function parameters).
///
/// \returns The NRVO candidate variable, if the return statement may use the
/// NRVO, or NULL if there is no such candidate.
@@ -1525,12 +1531,11 @@ Sema::PerformMoveOrCopyInitialization(const InitializedEntity &Entity,
// parameter of the selected constructor is not an rvalue reference
// to the object's type (possibly cv-qualified), overload resolution
// is performed again, considering the object as an lvalue.
- if (Seq.getKind() != InitializationSequence::FailedSequence) {
+ if (Seq) {
for (InitializationSequence::step_iterator Step = Seq.step_begin(),
StepEnd = Seq.step_end();
Step != StepEnd; ++Step) {
- if (Step->Kind
- != InitializationSequence::SK_ConstructorInitialization)
+ if (Step->Kind != InitializationSequence::SK_ConstructorInitialization)
continue;
CXXConstructorDecl *Constructor
@@ -1583,14 +1588,18 @@ Sema::ActOnBlockReturnStmt(SourceLocation ReturnLoc, Expr *RetValExp) {
if (Result.isInvalid())
return StmtError();
RetValExp = Result.take();
- CurBlock->ReturnType = RetValExp->getType();
- if (BlockDeclRefExpr *CDRE = dyn_cast<BlockDeclRefExpr>(RetValExp)) {
- // We have to remove a 'const' added to copied-in variable which was
- // part of the implementation spec. and not the actual qualifier for
- // the variable.
- if (CDRE->isConstQualAdded())
- CurBlock->ReturnType.removeLocalConst(); // FIXME: local???
- }
+
+ if (!RetValExp->isTypeDependent()) {
+ CurBlock->ReturnType = RetValExp->getType();
+ if (BlockDeclRefExpr *CDRE = dyn_cast<BlockDeclRefExpr>(RetValExp)) {
+ // We have to remove a 'const' added to copied-in variable which was
+ // part of the implementation spec. and not the actual qualifier for
+ // the variable.
+ if (CDRE->isConstQualAdded())
+ CurBlock->ReturnType.removeLocalConst(); // FIXME: local???
+ }
+ } else
+ CurBlock->ReturnType = Context.DependentTy;
} else
CurBlock->ReturnType = Context.VoidTy;
}
@@ -1607,13 +1616,17 @@ Sema::ActOnBlockReturnStmt(SourceLocation ReturnLoc, Expr *RetValExp) {
// compatibility to worry about here.
ReturnStmt *Result = 0;
if (CurBlock->ReturnType->isVoidType()) {
- if (RetValExp) {
+ if (RetValExp && !RetValExp->isTypeDependent() &&
+ (!getLangOptions().CPlusPlus || !RetValExp->getType()->isVoidType())) {
Diag(ReturnLoc, diag::err_return_block_has_expr);
RetValExp = 0;
}
Result = new (Context) ReturnStmt(ReturnLoc, RetValExp, 0);
} else if (!RetValExp) {
- return StmtError(Diag(ReturnLoc, diag::err_block_return_missing_expr));
+ if (!CurBlock->ReturnType->isDependentType())
+ return StmtError(Diag(ReturnLoc, diag::err_block_return_missing_expr));
+
+ Result = new (Context) ReturnStmt(ReturnLoc, 0, 0);
} else {
const VarDecl *NRVOCandidate = 0;
@@ -1652,7 +1665,7 @@ Sema::ActOnBlockReturnStmt(SourceLocation ReturnLoc, Expr *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() &&
+ if (getLangOptions().CPlusPlus && FnRetType->isRecordType() &&
!CurContext->isDependentContext())
FunctionScopes.back()->Returns.push_back(Result);
@@ -1661,44 +1674,62 @@ Sema::ActOnBlockReturnStmt(SourceLocation ReturnLoc, Expr *RetValExp) {
StmtResult
Sema::ActOnReturnStmt(SourceLocation ReturnLoc, Expr *RetValExp) {
+ // Check for unexpanded parameter packs.
+ if (RetValExp && DiagnoseUnexpandedParameterPack(RetValExp))
+ return StmtError();
+
if (getCurBlock())
return ActOnBlockReturnStmt(ReturnLoc, RetValExp);
QualType FnRetType;
+ QualType DeclaredRetType;
if (const FunctionDecl *FD = getCurFunctionDecl()) {
FnRetType = FD->getResultType();
+ DeclaredRetType = FnRetType;
if (FD->hasAttr<NoReturnAttr>() ||
FD->getType()->getAs<FunctionType>()->getNoReturnAttr())
Diag(ReturnLoc, diag::warn_noreturn_function_has_return_expr)
<< getCurFunctionOrMethodDecl()->getDeclName();
- } else if (ObjCMethodDecl *MD = getCurMethodDecl())
- FnRetType = MD->getResultType();
- else // If we don't have a function/method context, bail.
+ } else if (ObjCMethodDecl *MD = getCurMethodDecl()) {
+ DeclaredRetType = MD->getResultType();
+ if (MD->hasRelatedResultType() && MD->getClassInterface()) {
+ // In the implementation of a method with a related return type, the
+ // type used to type-check the validity of return statements within the
+ // method body is a pointer to the type of the class being implemented.
+ FnRetType = Context.getObjCInterfaceType(MD->getClassInterface());
+ FnRetType = Context.getObjCObjectPointerType(FnRetType);
+ } else {
+ FnRetType = DeclaredRetType;
+ }
+ } 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)
- unsigned D = diag::ext_return_has_expr;
- if (RetValExp->getType()->isVoidType())
- D = diag::ext_return_has_void_expr;
- else {
- ExprResult Result = Owned(RetValExp);
- Result = IgnoredValueConversions(Result.take());
- if (Result.isInvalid())
- return StmtError();
- RetValExp = Result.take();
- RetValExp = ImpCastExprToType(RetValExp, Context.VoidTy, CK_ToVoid).take();
- }
+ if (RetValExp) {
+ if (!RetValExp->isTypeDependent()) {
+ // C99 6.8.6.4p1 (ext_ since GCC warns)
+ unsigned D = diag::ext_return_has_expr;
+ if (RetValExp->getType()->isVoidType())
+ D = diag::ext_return_has_void_expr;
+ else {
+ ExprResult Result = Owned(RetValExp);
+ Result = IgnoredValueConversions(Result.take());
+ if (Result.isInvalid())
+ return StmtError();
+ RetValExp = Result.take();
+ RetValExp = ImpCastExprToType(RetValExp,
+ Context.VoidTy, CK_ToVoid).take();
+ }
- // return (some void expression); is legal in C++.
- if (D != diag::ext_return_has_void_expr ||
- !getLangOptions().CPlusPlus) {
- NamedDecl *CurDecl = getCurFunctionOrMethodDecl();
- Diag(ReturnLoc, D)
- << CurDecl->getDeclName() << isa<ObjCMethodDecl>(CurDecl)
- << RetValExp->getSourceRange();
+ // return (some void expression); is legal in C++.
+ if (D != diag::ext_return_has_void_expr ||
+ !getLangOptions().CPlusPlus) {
+ NamedDecl *CurDecl = getCurFunctionOrMethodDecl();
+ Diag(ReturnLoc, D)
+ << CurDecl->getDeclName() << isa<ObjCMethodDecl>(CurDecl)
+ << RetValExp->getSourceRange();
+ }
}
CheckImplicitConversions(RetValExp, ReturnLoc);
@@ -1730,7 +1761,7 @@ Sema::ActOnReturnStmt(SourceLocation ReturnLoc, Expr *RetValExp) {
NRVOCandidate = getCopyElisionCandidate(FnRetType, RetValExp, false);
InitializedEntity Entity = InitializedEntity::InitializeResult(ReturnLoc,
FnRetType,
- NRVOCandidate != 0);
+ NRVOCandidate != 0);
ExprResult Res = PerformMoveOrCopyInitialization(Entity, NRVOCandidate,
FnRetType, RetValExp);
if (Res.isInvalid()) {
@@ -1744,6 +1775,17 @@ Sema::ActOnReturnStmt(SourceLocation ReturnLoc, Expr *RetValExp) {
}
if (RetValExp) {
+ // If we type-checked an Objective-C method's return type based
+ // on a related return type, we may need to adjust the return
+ // type again. Do so now.
+ if (DeclaredRetType != FnRetType) {
+ ExprResult result = PerformImplicitConversion(RetValExp,
+ DeclaredRetType,
+ AA_Returning);
+ if (result.isInvalid()) return StmtError();
+ RetValExp = result.take();
+ }
+
CheckImplicitConversions(RetValExp, ReturnLoc);
RetValExp = MaybeCreateExprWithCleanups(RetValExp);
}
@@ -2015,7 +2057,9 @@ StmtResult Sema::ActOnAsmStmt(SourceLocation AsmLoc, bool IsSimple,
if (InputDomain == AD_Int && OutputDomain == AD_Int &&
!isOperandMentioned(InputOpNo, Pieces) &&
InputExpr->isEvaluatable(Context)) {
- InputExpr = ImpCastExprToType(InputExpr, OutTy, CK_IntegralCast).take();
+ CastKind castKind =
+ (OutTy->isBooleanType() ? CK_IntegralToBoolean : CK_IntegralCast);
+ InputExpr = ImpCastExprToType(InputExpr, OutTy, castKind).take();
Exprs[InputOpNo] = InputExpr;
NS->setInputExpr(i, InputExpr);
continue;
@@ -2251,7 +2295,9 @@ Sema::ActOnSEHExceptBlock(SourceLocation Loc,
assert(FilterExpr && Block);
if(!FilterExpr->getType()->isIntegerType()) {
- return StmtError(Diag(FilterExpr->getExprLoc(), diag::err_filter_expression_integral) << FilterExpr->getType());
+ return StmtError(Diag(FilterExpr->getExprLoc(),
+ diag::err_filter_expression_integral)
+ << FilterExpr->getType());
}
return Owned(SEHExceptStmt::Create(Context,Loc,FilterExpr,Block));
diff --git a/lib/Sema/SemaTemplate.cpp b/lib/Sema/SemaTemplate.cpp
index ef09124..5d4caac 100644
--- a/lib/Sema/SemaTemplate.cpp
+++ b/lib/Sema/SemaTemplate.cpp
@@ -92,11 +92,9 @@ void Sema::FilterAcceptableTemplateNames(LookupResult &R) {
// ambiguity in certain cases (for example, if it is found in more than
// one base class). If all of the injected-class-names that are found
// refer to specializations of the same class template, and if the name
- // is followed by a template-argument-list, the reference refers to the
- // class template itself and not a specialization thereof, and is not
+ // is used as a template-name, the reference refers to the class
+ // template itself and not a specialization thereof, and is not
// ambiguous.
- //
- // FIXME: Will we eventually have to do the same for alias templates?
if (ClassTemplateDecl *ClassTmpl = dyn_cast<ClassTemplateDecl>(Repl))
if (!ClassTemplates.insert(ClassTmpl)) {
filter.erase();
@@ -199,7 +197,8 @@ TemplateNameKind Sema::isTemplateName(Scope *S,
// We'll do this lookup again later.
R.suppressDiagnostics();
} else {
- assert(isa<ClassTemplateDecl>(TD) || isa<TemplateTemplateParmDecl>(TD));
+ assert(isa<ClassTemplateDecl>(TD) || isa<TemplateTemplateParmDecl>(TD) ||
+ isa<TypeAliasTemplateDecl>(TD));
TemplateKind = TNK_Type_template;
}
}
@@ -603,8 +602,10 @@ Sema::CheckNonTypeTemplateParameterType(QualType T, SourceLocation Loc) {
T->isPointerType() ||
// -- reference to object or reference to function,
T->isReferenceType() ||
- // -- pointer to member.
+ // -- pointer to member,
T->isMemberPointerType() ||
+ // -- std::nullptr_t.
+ T->isNullPtrType() ||
// If T is a dependent type, we can't do the check now, so we
// assume that it is well-formed.
T->isDependentType())
@@ -919,7 +920,8 @@ Sema::CheckClassTemplate(Scope *S, unsigned TagSpec, TagUseKind TUK,
// the class-key shall agree in kind with the original class
// template declaration (7.1.5.3).
RecordDecl *PrevRecordDecl = PrevClassTemplate->getTemplatedDecl();
- if (!isAcceptableTagRedeclaration(PrevRecordDecl, Kind, KWLoc, *Name)) {
+ if (!isAcceptableTagRedeclaration(PrevRecordDecl, Kind,
+ TUK == TUK_Definition, KWLoc, *Name)) {
Diag(KWLoc, diag::err_use_with_wrong_tag)
<< Name
<< FixItHint::CreateReplacement(KWLoc, PrevRecordDecl->getKindName());
@@ -1062,6 +1064,7 @@ static bool DiagnoseDefaultTemplateArgument(Sema &S,
SourceRange DefArgRange) {
switch (TPC) {
case Sema::TPC_ClassTemplate:
+ case Sema::TPC_TypeAliasTemplate:
return false;
case Sema::TPC_FunctionTemplate:
@@ -1187,9 +1190,10 @@ bool Sema::CheckTemplateParameterList(TemplateParameterList *NewParams,
bool MissingDefaultArg = false;
// C++0x [temp.param]p11:
- // If a template parameter of a primary class template is a template
- // parameter pack, it shall be the last template parameter.
- if (SawParameterPack && TPC == TPC_ClassTemplate) {
+ // If a template parameter of a primary class template or alias template
+ // is a template parameter pack, it shall be the last template parameter.
+ if (SawParameterPack &&
+ (TPC == TPC_ClassTemplate || TPC == TPC_TypeAliasTemplate)) {
Diag(ParameterPackLoc,
diag::err_template_param_pack_must_be_last_template_parameter);
Invalid = true;
@@ -1429,19 +1433,41 @@ struct DependencyChecker : RecursiveASTVisitor<DependencyChecker> {
}
return super::VisitDeclRefExpr(E);
}
+
+ bool TraverseInjectedClassNameType(const InjectedClassNameType *T) {
+ return TraverseType(T->getInjectedSpecializationType());
+ }
};
}
-/// Determines whether a template-id depends on the given parameter
+/// Determines whether a given type depends on the given parameter
/// list.
static bool
-DependsOnTemplateParameters(const TemplateSpecializationType *TemplateId,
- TemplateParameterList *Params) {
+DependsOnTemplateParameters(QualType T, TemplateParameterList *Params) {
DependencyChecker Checker(Params);
- Checker.TraverseType(QualType(TemplateId, 0));
+ Checker.TraverseType(T);
return Checker.Match;
}
+// Find the source range corresponding to the named type in the given
+// nested-name-specifier, if any.
+static SourceRange getRangeOfTypeInNestedNameSpecifier(ASTContext &Context,
+ QualType T,
+ const CXXScopeSpec &SS) {
+ NestedNameSpecifierLoc NNSLoc(SS.getScopeRep(), SS.location_data());
+ while (NestedNameSpecifier *NNS = NNSLoc.getNestedNameSpecifier()) {
+ if (const Type *CurType = NNS->getAsType()) {
+ if (Context.hasSameUnqualifiedType(T, QualType(CurType, 0)))
+ return NNSLoc.getTypeLoc().getSourceRange();
+ } else
+ break;
+
+ NNSLoc = NNSLoc.getPrefix();
+ }
+
+ return SourceRange();
+}
+
/// \brief Match the given template parameter lists to the given scope
/// specifier, returning the template parameter list that applies to the
/// name.
@@ -1449,6 +1475,8 @@ DependsOnTemplateParameters(const TemplateSpecializationType *TemplateId,
/// \param DeclStartLoc the start of the declaration that has a scope
/// specifier or a template parameter list.
///
+/// \param DeclLoc The location of the declaration itself.
+///
/// \param SS the scope specifier that will be matched to the given template
/// parameter lists. This scope specifier precedes a qualified name that is
/// being declared.
@@ -1473,6 +1501,7 @@ DependsOnTemplateParameters(const TemplateSpecializationType *TemplateId,
/// itself a template).
TemplateParameterList *
Sema::MatchTemplateParametersToScopeSpecifier(SourceLocation DeclStartLoc,
+ SourceLocation DeclLoc,
const CXXScopeSpec &SS,
TemplateParameterList **ParamLists,
unsigned NumParamLists,
@@ -1480,138 +1509,268 @@ Sema::MatchTemplateParametersToScopeSpecifier(SourceLocation DeclStartLoc,
bool &IsExplicitSpecialization,
bool &Invalid) {
IsExplicitSpecialization = false;
-
- // Find the template-ids that occur within the nested-name-specifier. These
- // template-ids will match up with the template parameter lists.
- llvm::SmallVector<const TemplateSpecializationType *, 4>
- TemplateIdsInSpecifier;
- llvm::SmallVector<ClassTemplateSpecializationDecl *, 4>
- ExplicitSpecializationsInSpecifier;
- for (NestedNameSpecifier *NNS = (NestedNameSpecifier *)SS.getScopeRep();
- NNS; NNS = NNS->getPrefix()) {
- const Type *T = NNS->getAsType();
- if (!T) break;
-
- // C++0x [temp.expl.spec]p17:
- // A member or a member template may be nested within many
- // enclosing class templates. In an explicit specialization for
- // such a member, the member declaration shall be preceded by a
- // template<> for each enclosing class template that is
- // explicitly specialized.
- //
- // Following the existing practice of GNU and EDG, we allow a typedef of a
- // template specialization type.
- while (const TypedefType *TT = dyn_cast<TypedefType>(T))
- T = TT->getDecl()->getUnderlyingType().getTypePtr();
-
- if (const TemplateSpecializationType *SpecType
- = dyn_cast<TemplateSpecializationType>(T)) {
- TemplateDecl *Template = SpecType->getTemplateName().getAsTemplateDecl();
- if (!Template)
- continue; // FIXME: should this be an error? probably...
-
- if (const RecordType *Record = SpecType->getAs<RecordType>()) {
- ClassTemplateSpecializationDecl *SpecDecl
- = cast<ClassTemplateSpecializationDecl>(Record->getDecl());
- // If the nested name specifier refers to an explicit specialization,
- // we don't need a template<> header.
- if (SpecDecl->getSpecializationKind() == TSK_ExplicitSpecialization) {
- ExplicitSpecializationsInSpecifier.push_back(SpecDecl);
- continue;
+ Invalid = false;
+
+ // The sequence of nested types to which we will match up the template
+ // parameter lists. We first build this list by starting with the type named
+ // by the nested-name-specifier and walking out until we run out of types.
+ llvm::SmallVector<QualType, 4> NestedTypes;
+ QualType T;
+ if (SS.getScopeRep()) {
+ if (CXXRecordDecl *Record
+ = dyn_cast_or_null<CXXRecordDecl>(computeDeclContext(SS, true)))
+ T = Context.getTypeDeclType(Record);
+ else
+ T = QualType(SS.getScopeRep()->getAsType(), 0);
+ }
+
+ // If we found an explicit specialization that prevents us from needing
+ // 'template<>' headers, this will be set to the location of that
+ // explicit specialization.
+ SourceLocation ExplicitSpecLoc;
+
+ while (!T.isNull()) {
+ NestedTypes.push_back(T);
+
+ // Retrieve the parent of a record type.
+ if (CXXRecordDecl *Record = T->getAsCXXRecordDecl()) {
+ // If this type is an explicit specialization, we're done.
+ if (ClassTemplateSpecializationDecl *Spec
+ = dyn_cast<ClassTemplateSpecializationDecl>(Record)) {
+ if (!isa<ClassTemplatePartialSpecializationDecl>(Spec) &&
+ Spec->getSpecializationKind() == TSK_ExplicitSpecialization) {
+ ExplicitSpecLoc = Spec->getLocation();
+ break;
}
+ } else if (Record->getTemplateSpecializationKind()
+ == TSK_ExplicitSpecialization) {
+ ExplicitSpecLoc = Record->getLocation();
+ break;
+ }
+
+ if (TypeDecl *Parent = dyn_cast<TypeDecl>(Record->getParent()))
+ T = Context.getTypeDeclType(Parent);
+ else
+ T = QualType();
+ continue;
+ }
+
+ if (const TemplateSpecializationType *TST
+ = T->getAs<TemplateSpecializationType>()) {
+ if (TemplateDecl *Template = TST->getTemplateName().getAsTemplateDecl()) {
+ if (TypeDecl *Parent = dyn_cast<TypeDecl>(Template->getDeclContext()))
+ T = Context.getTypeDeclType(Parent);
+ else
+ T = QualType();
+ continue;
}
-
- TemplateIdsInSpecifier.push_back(SpecType);
}
- }
-
- // Reverse the list of template-ids in the scope specifier, so that we can
- // more easily match up the template-ids and the template parameter lists.
- std::reverse(TemplateIdsInSpecifier.begin(), TemplateIdsInSpecifier.end());
-
- SourceLocation FirstTemplateLoc = DeclStartLoc;
- if (NumParamLists)
- FirstTemplateLoc = ParamLists[0]->getTemplateLoc();
-
- // Match the template-ids found in the specifier to the template parameter
- // lists.
- unsigned ParamIdx = 0, TemplateIdx = 0;
- for (unsigned NumTemplateIds = TemplateIdsInSpecifier.size();
- TemplateIdx != NumTemplateIds; ++TemplateIdx) {
- const TemplateSpecializationType *TemplateId
- = TemplateIdsInSpecifier[TemplateIdx];
- bool DependentTemplateId = TemplateId->isDependentType();
-
- // In friend declarations we can have template-ids which don't
- // depend on the corresponding template parameter lists. But
- // assume that empty parameter lists are supposed to match this
- // template-id.
- if (IsFriend && ParamIdx < NumParamLists && ParamLists[ParamIdx]->size()) {
- if (!DependentTemplateId ||
- !DependsOnTemplateParameters(TemplateId, ParamLists[ParamIdx]))
- continue;
+
+ // Look one step prior in a dependent template specialization type.
+ if (const DependentTemplateSpecializationType *DependentTST
+ = T->getAs<DependentTemplateSpecializationType>()) {
+ if (NestedNameSpecifier *NNS = DependentTST->getQualifier())
+ T = QualType(NNS->getAsType(), 0);
+ else
+ T = QualType();
+ continue;
+ }
+
+ // Look one step prior in a dependent name type.
+ if (const DependentNameType *DependentName = T->getAs<DependentNameType>()){
+ if (NestedNameSpecifier *NNS = DependentName->getQualifier())
+ T = QualType(NNS->getAsType(), 0);
+ else
+ T = QualType();
+ continue;
+ }
+
+ // Retrieve the parent of an enumeration type.
+ if (const EnumType *EnumT = T->getAs<EnumType>()) {
+ // FIXME: Forward-declared enums require a TSK_ExplicitSpecialization
+ // check here.
+ EnumDecl *Enum = EnumT->getDecl();
+
+ // Get to the parent type.
+ if (TypeDecl *Parent = dyn_cast<TypeDecl>(Enum->getParent()))
+ T = Context.getTypeDeclType(Parent);
+ else
+ T = QualType();
+ continue;
}
- if (ParamIdx >= NumParamLists) {
- // We have a template-id without a corresponding template parameter
- // list.
+ T = QualType();
+ }
+ // Reverse the nested types list, since we want to traverse from the outermost
+ // to the innermost while checking template-parameter-lists.
+ std::reverse(NestedTypes.begin(), NestedTypes.end());
+
+ // C++0x [temp.expl.spec]p17:
+ // A member or a member template may be nested within many
+ // enclosing class templates. In an explicit specialization for
+ // such a member, the member declaration shall be preceded by a
+ // template<> for each enclosing class template that is
+ // explicitly specialized.
+ bool SawNonEmptyTemplateParameterList = false;
+ unsigned ParamIdx = 0;
+ for (unsigned TypeIdx = 0, NumTypes = NestedTypes.size(); TypeIdx != NumTypes;
+ ++TypeIdx) {
+ T = NestedTypes[TypeIdx];
+
+ // Whether we expect a 'template<>' header.
+ bool NeedEmptyTemplateHeader = false;
- // ...which is fine if this is a friend declaration.
- if (IsFriend) {
- IsExplicitSpecialization = true;
- break;
+ // Whether we expect a template header with parameters.
+ bool NeedNonemptyTemplateHeader = false;
+
+ // For a dependent type, the set of template parameters that we
+ // expect to see.
+ TemplateParameterList *ExpectedTemplateParams = 0;
+
+ // C++0x [temp.expl.spec]p15:
+ // A member or a member template may be nested within many enclosing
+ // class templates. In an explicit specialization for such a member, the
+ // member declaration shall be preceded by a template<> for each
+ // enclosing class template that is explicitly specialized.
+ if (CXXRecordDecl *Record = T->getAsCXXRecordDecl()) {
+ if (ClassTemplatePartialSpecializationDecl *Partial
+ = dyn_cast<ClassTemplatePartialSpecializationDecl>(Record)) {
+ ExpectedTemplateParams = Partial->getTemplateParameters();
+ NeedNonemptyTemplateHeader = true;
+ } else if (Record->isDependentType()) {
+ if (Record->getDescribedClassTemplate()) {
+ ExpectedTemplateParams = Record->getDescribedClassTemplate()
+ ->getTemplateParameters();
+ NeedNonemptyTemplateHeader = true;
+ }
+ } else if (ClassTemplateSpecializationDecl *Spec
+ = dyn_cast<ClassTemplateSpecializationDecl>(Record)) {
+ // C++0x [temp.expl.spec]p4:
+ // Members of an explicitly specialized class template are defined
+ // in the same manner as members of normal classes, and not using
+ // the template<> syntax.
+ if (Spec->getSpecializationKind() != TSK_ExplicitSpecialization)
+ NeedEmptyTemplateHeader = true;
+ else
+ continue;
+ } else if (Record->getTemplateSpecializationKind()) {
+ if (Record->getTemplateSpecializationKind()
+ != TSK_ExplicitSpecialization &&
+ TypeIdx == NumTypes - 1)
+ IsExplicitSpecialization = true;
+
+ continue;
}
-
- if (DependentTemplateId) {
- // FIXME: the location information here isn't great.
- Diag(SS.getRange().getBegin(),
- diag::err_template_spec_needs_template_parameters)
- << QualType(TemplateId, 0)
- << SS.getRange();
- Invalid = true;
- } else {
- Diag(SS.getRange().getBegin(), diag::err_template_spec_needs_header)
- << SS.getRange()
- << FixItHint::CreateInsertion(FirstTemplateLoc, "template<> ");
- IsExplicitSpecialization = true;
+ } else if (const TemplateSpecializationType *TST
+ = T->getAs<TemplateSpecializationType>()) {
+ if (TemplateDecl *Template = TST->getTemplateName().getAsTemplateDecl()) {
+ ExpectedTemplateParams = Template->getTemplateParameters();
+ NeedNonemptyTemplateHeader = true;
}
- return 0;
+ } else if (T->getAs<DependentTemplateSpecializationType>()) {
+ // FIXME: We actually could/should check the template arguments here
+ // against the corresponding template parameter list.
+ NeedNonemptyTemplateHeader = false;
+ }
+
+ // C++ [temp.expl.spec]p16:
+ // In an explicit specialization declaration for a member of a class
+ // template or a member template that ap- pears in namespace scope, the
+ // member template and some of its enclosing class templates may remain
+ // unspecialized, except that the declaration shall not explicitly
+ // specialize a class member template if its en- closing class templates
+ // are not explicitly specialized as well.
+ if (ParamIdx < NumParamLists) {
+ if (ParamLists[ParamIdx]->size() == 0) {
+ if (SawNonEmptyTemplateParameterList) {
+ Diag(DeclLoc, diag::err_specialize_member_of_template)
+ << ParamLists[ParamIdx]->getSourceRange();
+ Invalid = true;
+ IsExplicitSpecialization = false;
+ return 0;
+ }
+ } else
+ SawNonEmptyTemplateParameterList = true;
}
-
- // Check the template parameter list against its corresponding template-id.
- if (DependentTemplateId) {
- TemplateParameterList *ExpectedTemplateParams = 0;
-
- // Are there cases in (e.g.) friends where this won't match?
- if (const InjectedClassNameType *Injected
- = TemplateId->getAs<InjectedClassNameType>()) {
- CXXRecordDecl *Record = Injected->getDecl();
- if (ClassTemplatePartialSpecializationDecl *Partial =
- dyn_cast<ClassTemplatePartialSpecializationDecl>(Record))
- ExpectedTemplateParams = Partial->getTemplateParameters();
+
+ if (NeedEmptyTemplateHeader) {
+ // If we're on the last of the types, and we need a 'template<>' header
+ // here, then it's an explicit specialization.
+ if (TypeIdx == NumTypes - 1)
+ IsExplicitSpecialization = true;
+
+ if (ParamIdx < NumParamLists) {
+ if (ParamLists[ParamIdx]->size() > 0) {
+ // The header has template parameters when it shouldn't. Complain.
+ Diag(ParamLists[ParamIdx]->getTemplateLoc(),
+ diag::err_template_param_list_matches_nontemplate)
+ << T
+ << SourceRange(ParamLists[ParamIdx]->getLAngleLoc(),
+ ParamLists[ParamIdx]->getRAngleLoc())
+ << getRangeOfTypeInNestedNameSpecifier(Context, T, SS);
+ Invalid = true;
+ return 0;
+ }
+
+ // Consume this template header.
+ ++ParamIdx;
+ continue;
+ }
+
+ if (!IsFriend) {
+ // We don't have a template header, but we should.
+ SourceLocation ExpectedTemplateLoc;
+ if (NumParamLists > 0)
+ ExpectedTemplateLoc = ParamLists[0]->getTemplateLoc();
else
- ExpectedTemplateParams = Record->getDescribedClassTemplate()
- ->getTemplateParameters();
- }
+ ExpectedTemplateLoc = DeclStartLoc;
- if (ExpectedTemplateParams)
- TemplateParameterListsAreEqual(ParamLists[ParamIdx],
- ExpectedTemplateParams,
- true, TPL_TemplateMatch);
-
- CheckTemplateParameterList(ParamLists[ParamIdx], 0,
- TPC_ClassTemplateMember);
- } else if (ParamLists[ParamIdx]->size() > 0)
- Diag(ParamLists[ParamIdx]->getTemplateLoc(),
- diag::err_template_param_list_matches_nontemplate)
- << TemplateId
- << ParamLists[ParamIdx]->getSourceRange();
- else
- IsExplicitSpecialization = true;
+ Diag(DeclLoc, diag::err_template_spec_needs_header)
+ << getRangeOfTypeInNestedNameSpecifier(Context, T, SS)
+ << FixItHint::CreateInsertion(ExpectedTemplateLoc, "template<> ");
+ }
+
+ continue;
+ }
+
+ if (NeedNonemptyTemplateHeader) {
+ // In friend declarations we can have template-ids which don't
+ // depend on the corresponding template parameter lists. But
+ // assume that empty parameter lists are supposed to match this
+ // template-id.
+ if (IsFriend && T->isDependentType()) {
+ if (ParamIdx < NumParamLists &&
+ DependsOnTemplateParameters(T, ParamLists[ParamIdx]))
+ ExpectedTemplateParams = 0;
+ else
+ continue;
+ }
- ++ParamIdx;
+ if (ParamIdx < NumParamLists) {
+ // Check the template parameter list, if we can.
+ if (ExpectedTemplateParams &&
+ !TemplateParameterListsAreEqual(ParamLists[ParamIdx],
+ ExpectedTemplateParams,
+ true, TPL_TemplateMatch))
+ Invalid = true;
+
+ if (!Invalid &&
+ CheckTemplateParameterList(ParamLists[ParamIdx], 0,
+ TPC_ClassTemplateMember))
+ Invalid = true;
+
+ ++ParamIdx;
+ continue;
+ }
+
+ Diag(DeclLoc, diag::err_template_spec_needs_template_parameters)
+ << T
+ << getRangeOfTypeInNestedNameSpecifier(Context, T, SS);
+ Invalid = true;
+ continue;
+ }
}
-
+
// If there were at least as many template-ids as there were template
// parameter lists, then there are no template parameter lists remaining for
// the declaration itself.
@@ -1619,32 +1778,53 @@ Sema::MatchTemplateParametersToScopeSpecifier(SourceLocation DeclStartLoc,
return 0;
// If there were too many template parameter lists, complain about that now.
- if (ParamIdx != NumParamLists - 1) {
- while (ParamIdx < NumParamLists - 1) {
- bool isExplicitSpecHeader = ParamLists[ParamIdx]->size() == 0;
- Diag(ParamLists[ParamIdx]->getTemplateLoc(),
- isExplicitSpecHeader? diag::warn_template_spec_extra_headers
- : diag::err_template_spec_extra_headers)
- << SourceRange(ParamLists[ParamIdx]->getTemplateLoc(),
- ParamLists[ParamIdx]->getRAngleLoc());
-
- if (isExplicitSpecHeader && !ExplicitSpecializationsInSpecifier.empty()) {
- Diag(ExplicitSpecializationsInSpecifier.back()->getLocation(),
- diag::note_explicit_template_spec_does_not_need_header)
- << ExplicitSpecializationsInSpecifier.back();
- ExplicitSpecializationsInSpecifier.pop_back();
- }
-
- // We have a template parameter list with no corresponding scope, which
- // means that the resulting template declaration can't be instantiated
- // properly (we'll end up with dependent nodes when we shouldn't).
- if (!isExplicitSpecHeader)
- Invalid = true;
-
- ++ParamIdx;
+ if (ParamIdx < NumParamLists - 1) {
+ bool HasAnyExplicitSpecHeader = false;
+ bool AllExplicitSpecHeaders = true;
+ for (unsigned I = ParamIdx; I != NumParamLists - 1; ++I) {
+ if (ParamLists[I]->size() == 0)
+ HasAnyExplicitSpecHeader = true;
+ else
+ AllExplicitSpecHeaders = false;
}
+
+ Diag(ParamLists[ParamIdx]->getTemplateLoc(),
+ AllExplicitSpecHeaders? diag::warn_template_spec_extra_headers
+ : diag::err_template_spec_extra_headers)
+ << SourceRange(ParamLists[ParamIdx]->getTemplateLoc(),
+ ParamLists[NumParamLists - 2]->getRAngleLoc());
+
+ // If there was a specialization somewhere, such that 'template<>' is
+ // not required, and there were any 'template<>' headers, note where the
+ // specialization occurred.
+ if (ExplicitSpecLoc.isValid() && HasAnyExplicitSpecHeader)
+ Diag(ExplicitSpecLoc,
+ diag::note_explicit_template_spec_does_not_need_header)
+ << NestedTypes.back();
+
+ // We have a template parameter list with no corresponding scope, which
+ // means that the resulting template declaration can't be instantiated
+ // properly (we'll end up with dependent nodes when we shouldn't).
+ if (!AllExplicitSpecHeaders)
+ Invalid = true;
}
+ // C++ [temp.expl.spec]p16:
+ // In an explicit specialization declaration for a member of a class
+ // template or a member template that ap- pears in namespace scope, the
+ // member template and some of its enclosing class templates may remain
+ // unspecialized, except that the declaration shall not explicitly
+ // specialize a class member template if its en- closing class templates
+ // are not explicitly specialized as well.
+ if (ParamLists[NumParamLists - 1]->size() == 0 &&
+ SawNonEmptyTemplateParameterList) {
+ Diag(DeclLoc, diag::err_specialize_member_of_template)
+ << ParamLists[ParamIdx]->getSourceRange();
+ Invalid = true;
+ IsExplicitSpecialization = false;
+ return 0;
+ }
+
// Return the last template parameter list, which corresponds to the
// entity being declared.
return ParamLists[NumParamLists - 1];
@@ -1655,7 +1835,8 @@ void Sema::NoteAllFoundTemplates(TemplateName Name) {
Diag(Template->getLocation(), diag::note_template_declared_here)
<< (isa<FunctionTemplateDecl>(Template)? 0
: isa<ClassTemplateDecl>(Template)? 1
- : 2)
+ : isa<TypeAliasTemplateDecl>(Template)? 2
+ : 3)
<< Template->getDeclName();
return;
}
@@ -1675,13 +1856,24 @@ void Sema::NoteAllFoundTemplates(TemplateName Name) {
QualType Sema::CheckTemplateIdType(TemplateName Name,
SourceLocation TemplateLoc,
TemplateArgumentListInfo &TemplateArgs) {
+ DependentTemplateName *DTN = Name.getAsDependentTemplateName();
+ if (DTN && DTN->isIdentifier())
+ // When building a template-id where the template-name is dependent,
+ // assume the template is a type template. Either our assumption is
+ // correct, or the code is ill-formed and will be diagnosed when the
+ // dependent name is substituted.
+ return Context.getDependentTemplateSpecializationType(ETK_None,
+ DTN->getQualifier(),
+ DTN->getIdentifier(),
+ TemplateArgs);
+
TemplateDecl *Template = Name.getAsTemplateDecl();
if (!Template || isa<FunctionTemplateDecl>(Template)) {
// We might have a substituted template template parameter pack. If so,
// build a template specialization type for it.
if (Name.getAsSubstTemplateTemplateParmPack())
return Context.getTemplateSpecializationType(Name, TemplateArgs);
-
+
Diag(TemplateLoc, diag::err_template_id_not_a_type)
<< Name;
NoteAllFoundTemplates(Name);
@@ -1700,9 +1892,32 @@ QualType Sema::CheckTemplateIdType(TemplateName Name,
QualType CanonType;
- if (Name.isDependent() ||
- TemplateSpecializationType::anyDependentTemplateArguments(
- TemplateArgs)) {
+ if (TypeAliasTemplateDecl *AliasTemplate
+ = dyn_cast<TypeAliasTemplateDecl>(Template)) {
+ // Find the canonical type for this type alias template specialization.
+ TypeAliasDecl *Pattern = AliasTemplate->getTemplatedDecl();
+ if (Pattern->isInvalidDecl())
+ return QualType();
+
+ TemplateArgumentList TemplateArgs(TemplateArgumentList::OnStack,
+ Converted.data(), Converted.size());
+
+ // Only substitute for the innermost template argument list.
+ MultiLevelTemplateArgumentList TemplateArgLists;
+ TemplateArgLists.addOuterTemplateArguments(&TemplateArgs);
+ unsigned Depth = AliasTemplate->getTemplateParameters()->getDepth();
+ for (unsigned I = 0; I < Depth; ++I)
+ TemplateArgLists.addOuterTemplateArguments(0, 0);
+
+ InstantiatingTemplate Inst(*this, TemplateLoc, Template);
+ CanonType = SubstType(Pattern->getUnderlyingType(),
+ TemplateArgLists, AliasTemplate->getLocation(),
+ AliasTemplate->getDeclName());
+ if (CanonType.isNull())
+ return QualType();
+ } else if (Name.isDependent() ||
+ TemplateSpecializationType::anyDependentTemplateArguments(
+ TemplateArgs)) {
// This class template specialization is a dependent
// type. Therefore, its canonical type is another class template
// specialization type that contains all of the converted
@@ -1894,6 +2109,16 @@ TypeResult Sema::ActOnTagTemplateIdType(TagUseKind TUK,
SpecTL.setArgLocInfo(I, TemplateArgs[I].getLocInfo());
return CreateParsedType(T, TLB.getTypeSourceInfo(Context, T));
}
+
+ if (TypeAliasTemplateDecl *TAT =
+ dyn_cast_or_null<TypeAliasTemplateDecl>(Template.getAsTemplateDecl())) {
+ // C++0x [dcl.type.elab]p2:
+ // If the identifier resolves to a typedef-name or the simple-template-id
+ // resolves to an alias template specialization, the
+ // elaborated-type-specifier is ill-formed.
+ Diag(TemplateLoc, diag::err_tag_reference_non_tag) << 4;
+ Diag(TAT->getLocation(), diag::note_declared_at);
+ }
QualType Result = CheckTemplateIdType(Template, TemplateLoc, TemplateArgs);
if (Result.isNull())
@@ -1906,7 +2131,8 @@ TypeResult Sema::ActOnTagTemplateIdType(TagUseKind TUK,
IdentifierInfo *Id = D->getIdentifier();
assert(Id && "templated class must have an identifier");
- if (!isAcceptableTagRedeclaration(D, TagKind, TagLoc, *Id)) {
+ if (!isAcceptableTagRedeclaration(D, TagKind, TUK == TUK_Definition,
+ TagLoc, *Id)) {
Diag(TagLoc, diag::err_use_with_wrong_tag)
<< Result
<< FixItHint::CreateReplacement(SourceRange(TagLoc), D->getKindName());
@@ -2485,7 +2711,7 @@ bool Sema::CheckTemplateArgument(NamedDecl *Param,
}
// We have a template argument that actually does refer to a class
- // template, template alias, or template template parameter, and
+ // template, alias template, or template template parameter, and
// therefore cannot be a non-type template argument.
Diag(Arg.getLocation(), diag::err_template_arg_must_be_expr)
<< Arg.getSourceRange();
@@ -2562,7 +2788,8 @@ bool Sema::CheckTemplateArgument(NamedDecl *Param,
case TemplateArgument::Type:
// We have a template template parameter but the template
// argument does not refer to a template.
- Diag(Arg.getLocation(), diag::err_template_arg_must_be_template);
+ Diag(Arg.getLocation(), diag::err_template_arg_must_be_template)
+ << getLangOptions().CPlusPlus0x;
return true;
case TemplateArgument::Declaration:
@@ -2631,9 +2858,6 @@ bool Sema::CheckTemplateArgumentList(TemplateDecl *Template,
unsigned ArgIdx = 0;
LocalInstantiationScope InstScope(*this, true);
while (Param != ParamEnd) {
- if (ArgIdx > NumArgs && PartialTemplateArgs)
- break;
-
if (ArgIdx < NumArgs) {
// If we have an expanded parameter pack, make sure we don't have too
// many arguments.
@@ -2674,11 +2898,31 @@ bool Sema::CheckTemplateArgumentList(TemplateDecl *Template,
continue;
}
+ // If we're checking a partial template argument list, we're done.
+ if (PartialTemplateArgs) {
+ if ((*Param)->isTemplateParameterPack() && !ArgumentPack.empty())
+ Converted.push_back(TemplateArgument::CreatePackCopy(Context,
+ ArgumentPack.data(),
+ ArgumentPack.size()));
+
+ return Invalid;
+ }
+
// If we have a template parameter pack with no more corresponding
// arguments, just break out now and we'll fill in the argument pack below.
if ((*Param)->isTemplateParameterPack())
break;
+ // If our template is a template template parameter that hasn't acquired
+ // its proper context yet (e.g., because we're using the template template
+ // parameter in the signature of a function template, before we've built
+ // the function template itself), don't attempt substitution of default
+ // template arguments at this point: we don't have enough context to
+ // do it properly.
+ if (isTemplateTemplateParameter &&
+ Template->getDeclContext()->isTranslationUnit())
+ break;
+
// We have a default template argument that we will use.
TemplateArgumentLoc Arg;
@@ -2689,7 +2933,7 @@ bool Sema::CheckTemplateArgumentList(TemplateDecl *Template,
// the default argument.
if (TemplateTypeParmDecl *TTP = dyn_cast<TemplateTypeParmDecl>(*Param)) {
if (!TTP->hasDefaultArgument()) {
- assert((Invalid || PartialTemplateArgs) && "Missing default argument");
+ assert(Invalid && "Missing default argument");
break;
}
@@ -2707,7 +2951,7 @@ bool Sema::CheckTemplateArgumentList(TemplateDecl *Template,
} else if (NonTypeTemplateParmDecl *NTTP
= dyn_cast<NonTypeTemplateParmDecl>(*Param)) {
if (!NTTP->hasDefaultArgument()) {
- assert((Invalid || PartialTemplateArgs) && "Missing default argument");
+ assert(Invalid && "Missing default argument");
break;
}
@@ -2726,7 +2970,7 @@ bool Sema::CheckTemplateArgumentList(TemplateDecl *Template,
= cast<TemplateTemplateParmDecl>(*Param);
if (!TempParm->hasDefaultArgument()) {
- assert((Invalid || PartialTemplateArgs) && "Missing default argument");
+ assert(Invalid && "Missing default argument");
break;
}
@@ -2772,9 +3016,7 @@ bool Sema::CheckTemplateArgumentList(TemplateDecl *Template,
// in arguments for non-template parameter packs.
if ((*Param)->isTemplateParameterPack()) {
- if (PartialTemplateArgs && ArgumentPack.empty()) {
- Converted.push_back(TemplateArgument());
- } else if (ArgumentPack.empty())
+ if (ArgumentPack.empty())
Converted.push_back(TemplateArgument(0, 0));
else {
Converted.push_back(TemplateArgument::CreatePackCopy(Context,
@@ -2918,6 +3160,11 @@ bool UnnamedLocalNoLinkageFinder::VisitDecltypeType(const DecltypeType*) {
return false;
}
+bool UnnamedLocalNoLinkageFinder::VisitUnaryTransformType(
+ const UnaryTransformType*) {
+ return false;
+}
+
bool UnnamedLocalNoLinkageFinder::VisitAutoType(const AutoType *T) {
return Visit(T->getDeducedType());
}
@@ -3501,32 +3748,49 @@ ExprResult Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
return ExprError();
}
+ // Add the value of this argument to the list of converted
+ // arguments. We use the bitwidth and signedness of the template
+ // parameter.
+ if (Arg->isValueDependent()) {
+ // The argument is value-dependent. Create a new
+ // TemplateArgument with the converted expression.
+ Converted = TemplateArgument(Arg);
+ return Owned(Arg);
+ }
+
QualType IntegerType = Context.getCanonicalType(ParamType);
if (const EnumType *Enum = IntegerType->getAs<EnumType>())
IntegerType = Context.getCanonicalType(Enum->getDecl()->getIntegerType());
- if (!Arg->isValueDependent()) {
+ if (ParamType->isBooleanType()) {
+ // Value must be zero or one.
+ Value = Value != 0;
+ unsigned AllowedBits = Context.getTypeSize(IntegerType);
+ if (Value.getBitWidth() != AllowedBits)
+ Value = Value.extOrTrunc(AllowedBits);
+ Value.setIsSigned(IntegerType->isSignedIntegerOrEnumerationType());
+ } else {
llvm::APSInt OldValue = Value;
-
+
// Coerce the template argument's value to the value it will have
// based on the template parameter's type.
unsigned AllowedBits = Context.getTypeSize(IntegerType);
if (Value.getBitWidth() != AllowedBits)
Value = Value.extOrTrunc(AllowedBits);
- Value.setIsSigned(IntegerType->isSignedIntegerType());
-
+ Value.setIsSigned(IntegerType->isSignedIntegerOrEnumerationType());
+
// Complain if an unsigned parameter received a negative value.
- if (IntegerType->isUnsignedIntegerType()
- && (OldValue.isSigned() && OldValue.isNegative())) {
+ if (IntegerType->isUnsignedIntegerOrEnumerationType()
+ && (OldValue.isSigned() && OldValue.isNegative())) {
Diag(Arg->getSourceRange().getBegin(), diag::warn_template_arg_negative)
<< OldValue.toString(10) << Value.toString(10) << Param->getType()
<< Arg->getSourceRange();
Diag(Param->getLocation(), diag::note_template_param_here);
}
-
+
// Complain if we overflowed the template parameter's type.
unsigned RequiredBits;
- if (IntegerType->isUnsignedIntegerType())
+ if (IntegerType->isUnsignedIntegerOrEnumerationType())
RequiredBits = OldValue.getActiveBits();
else if (OldValue.isUnsigned())
RequiredBits = OldValue.getActiveBits() + 1;
@@ -3541,16 +3805,6 @@ ExprResult Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
}
}
- // Add the value of this argument to the list of converted
- // arguments. We use the bitwidth and signedness of the template
- // parameter.
- if (Arg->isValueDependent()) {
- // The argument is value-dependent. Create a new
- // TemplateArgument with the converted expression.
- Converted = TemplateArgument(Arg);
- return Owned(Arg);
- }
-
Converted = TemplateArgument(Value,
ParamType->isEnumeralType() ? ParamType
: IntegerType);
@@ -3563,10 +3817,17 @@ ExprResult Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
// from a template argument of type std::nullptr_t to a non-type
// template parameter of type pointer to object, pointer to
// function, or pointer-to-member, respectively.
- if (ArgType->isNullPtrType() &&
- (ParamType->isPointerType() || ParamType->isMemberPointerType())) {
- Converted = TemplateArgument((NamedDecl *)0);
- return Owned(Arg);
+ if (ArgType->isNullPtrType()) {
+ if (ParamType->isPointerType() || ParamType->isMemberPointerType()) {
+ Converted = TemplateArgument((NamedDecl *)0);
+ return Owned(Arg);
+ }
+
+ if (ParamType->isNullPtrType()) {
+ llvm::APSInt Zero(Context.getTypeSize(Context.NullPtrTy), true);
+ Converted = TemplateArgument(Zero, Context.NullPtrTy);
+ return Owned(Arg);
+ }
}
// Handle pointer-to-function, reference-to-function, and
@@ -3715,9 +3976,10 @@ bool Sema::CheckTemplateArgument(TemplateTemplateParmDecl *Param,
return false;
}
- // C++ [temp.arg.template]p1:
+ // C++0x [temp.arg.template]p1:
// A template-argument for a template template-parameter shall be
- // the name of a class template, expressed as id-expression. Only
+ // the name of a class template or an alias template, expressed as an
+ // id-expression. When the template-argument names a class template, only
// primary class templates are considered when matching the
// template template argument with the corresponding parameter;
// partial specializations are not considered even if their
@@ -3727,7 +3989,8 @@ bool Sema::CheckTemplateArgument(TemplateTemplateParmDecl *Param,
// will happen when we are dealing with, e.g., class template
// partial specializations.
if (!isa<ClassTemplateDecl>(Template) &&
- !isa<TemplateTemplateParmDecl>(Template)) {
+ !isa<TemplateTemplateParmDecl>(Template) &&
+ !isa<TypeAliasTemplateDecl>(Template)) {
assert(isa<FunctionTemplateDecl>(Template) &&
"Only function templates are possible here");
Diag(Arg.getLocation(), diag::err_template_arg_not_class_template);
@@ -3858,6 +4121,9 @@ Sema::BuildExpressionFromIntegralTemplateArgument(const TemplateArgument &Arg,
Arg.getAsIntegral()->getBoolValue(),
T, Loc));
+ if (T->isNullPtrType())
+ return Owned(new (Context) CXXNullPtrLiteralExpr(Context.NullPtrTy, Loc));
+
// If this is an enum type that we're instantiating, we need to use an integer
// type the same size as the enumerator. We don't want to build an
// IntegerLiteral with enum type.
@@ -4044,7 +4310,7 @@ Sema::TemplateParameterListsAreEqual(TemplateParameterList *New,
// C++0x [temp.arg.template]p3:
// A template-argument matches a template template-parameter (call it P)
// when each of the template parameters in the template-parameter-list of
- // the template-argument's corresponding class template or template alias
+ // the template-argument's corresponding class template or alias template
// (call it A) matches the corresponding template parameter in the
// template-parameter-list of P. [...]
TemplateParameterList::iterator NewParm = New->begin();
@@ -4442,7 +4708,9 @@ Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec,
// friend declarations.
bool Invalid = false;
TemplateParameterList *TemplateParams
- = MatchTemplateParametersToScopeSpecifier(TemplateNameLoc, SS,
+ = MatchTemplateParametersToScopeSpecifier(TemplateNameLoc,
+ TemplateNameLoc,
+ SS,
(TemplateParameterList**)TemplateParameterLists.get(),
TemplateParameterLists.size(),
TUK == TUK_Friend,
@@ -4509,7 +4777,7 @@ Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec,
TagTypeKind Kind = TypeWithKeyword::getTagTypeKindForTypeSpec(TagSpec);
assert(Kind != TTK_Enum && "Invalid enum tag in class template spec!");
if (!isAcceptableTagRedeclaration(ClassTemplate->getTemplatedDecl(),
- Kind, KWLoc,
+ Kind, TUK == TUK_Definition, KWLoc,
*ClassTemplate->getIdentifier())) {
Diag(KWLoc, diag::err_use_with_wrong_tag)
<< ClassTemplate
@@ -5180,7 +5448,7 @@ Sema::CheckFunctionTemplateSpecialization(FunctionDecl *FD,
SpecInfo->getPointOfInstantiation(),
HasNoEffect))
return true;
-
+
// Mark the prior declaration as an explicit specialization, so that later
// clients know that this is an explicit specialization.
if (!isFriend) {
@@ -5200,7 +5468,8 @@ Sema::CheckFunctionTemplateSpecialization(FunctionDecl *FD,
TemplArgs, /*InsertPos=*/0,
SpecInfo->getTemplateSpecializationKind(),
TemplArgsAsWritten);
-
+ FD->setStorageClass(Specialization->getStorageClass());
+
// The "previous declaration" for this function template specialization is
// the prior function template specialization.
Previous.clear();
@@ -5479,7 +5748,7 @@ Sema::ActOnExplicitInstantiation(Scope *S,
assert(Kind != TTK_Enum &&
"Invalid enum tag in class template explicit instantiation!");
if (!isAcceptableTagRedeclaration(ClassTemplate->getTemplatedDecl(),
- Kind, KWLoc,
+ Kind, /*isDefinition*/false, KWLoc,
*ClassTemplate->getIdentifier())) {
Diag(KWLoc, diag::err_use_with_wrong_tag)
<< ClassTemplate
@@ -5801,11 +6070,20 @@ DeclResult Sema::ActOnExplicitInstantiation(Scope *S,
if (R.isNull())
return true;
+ // C++ [dcl.stc]p1:
+ // A storage-class-specifier shall not be specified in [...] an explicit
+ // instantiation (14.7.2) directive.
if (D.getDeclSpec().getStorageClassSpec() == DeclSpec::SCS_typedef) {
- // Cannot explicitly instantiate a typedef.
Diag(D.getIdentifierLoc(), diag::err_explicit_instantiation_of_typedef)
<< Name;
return true;
+ } else if (D.getDeclSpec().getStorageClassSpec()
+ != DeclSpec::SCS_unspecified) {
+ // Complain about then remove the storage class specifier.
+ Diag(D.getIdentifierLoc(), diag::err_explicit_instantiation_storage_class)
+ << FixItHint::CreateRemoval(D.getDeclSpec().getStorageClassSpecLoc());
+
+ D.getMutableDeclSpec().ClearStorageClassSpecs();
}
// C++0x [temp.explicit]p1:
diff --git a/lib/Sema/SemaTemplateDeduction.cpp b/lib/Sema/SemaTemplateDeduction.cpp
index 235af04..7d0ce8b 100644
--- a/lib/Sema/SemaTemplateDeduction.cpp
+++ b/lib/Sema/SemaTemplateDeduction.cpp
@@ -2314,7 +2314,7 @@ Sema::FinishTemplateArgumentDeduction(FunctionTemplateDecl *FunctionTemplate,
FunctionTemplate->getLocation(),
FunctionTemplate->getSourceRange().getEnd(),
0, Builder,
- CTAK_Deduced)) {
+ CTAK_Specified)) {
Info.Param = makeTemplateParameter(
const_cast<NamedDecl *>(TemplateParams->getParam(I)));
// FIXME: These template arguments are temporary. Free them!
@@ -2500,6 +2500,12 @@ static bool AdjustFunctionParmAndArgTypesForDeduction(Sema &S,
if (ParamRefType) {
QualType PointeeType = ParamRefType->getPointeeType();
+ // If the argument has incomplete array type, try to complete it's type.
+ if (ArgType->isIncompleteArrayType() &&
+ !S.RequireCompleteExprType(Arg, S.PDiag(),
+ std::make_pair(SourceLocation(), S.PDiag())))
+ ArgType = Arg->getType();
+
// [C++0x] If P is an rvalue reference to a cv-unqualified
// template parameter and the argument is an lvalue, the type
// "lvalue reference to A" is used in place of A for type
@@ -2507,7 +2513,9 @@ static bool AdjustFunctionParmAndArgTypesForDeduction(Sema &S,
if (isa<RValueReferenceType>(ParamType)) {
if (!PointeeType.getQualifiers() &&
isa<TemplateTypeParmType>(PointeeType) &&
- Arg->Classify(S.Context).isLValue())
+ Arg->Classify(S.Context).isLValue() &&
+ Arg->getType() != S.Context.OverloadTy &&
+ Arg->getType() != S.Context.BoundMemberTy)
ArgType = S.Context.getLValueReferenceType(ArgType);
}
@@ -3884,6 +3892,13 @@ MarkUsedTemplateParameters(Sema &SemaRef, QualType T,
OnlyDeduced, Depth, Used);
break;
+ case Type::UnaryTransform:
+ if (!OnlyDeduced)
+ MarkUsedTemplateParameters(SemaRef,
+ cast<UnaryTransformType>(T)->getUnderlyingType(),
+ OnlyDeduced, Depth, Used);
+ break;
+
case Type::PackExpansion:
MarkUsedTemplateParameters(SemaRef,
cast<PackExpansionType>(T)->getPattern(),
diff --git a/lib/Sema/SemaTemplateInstantiate.cpp b/lib/Sema/SemaTemplateInstantiate.cpp
index 92ba095..3c19641 100644
--- a/lib/Sema/SemaTemplateInstantiate.cpp
+++ b/lib/Sema/SemaTemplateInstantiate.cpp
@@ -13,6 +13,7 @@
#include "clang/Sema/SemaInternal.h"
#include "TreeTransform.h"
#include "clang/Sema/DeclSpec.h"
+#include "clang/Sema/Initialization.h"
#include "clang/Sema/Lookup.h"
#include "clang/Sema/Template.h"
#include "clang/Sema/TemplateDeduction.h"
@@ -58,9 +59,13 @@ Sema::getTemplateInstantiationArgs(NamedDecl *D,
Result.addOuterTemplateArguments(Innermost);
DeclContext *Ctx = dyn_cast<DeclContext>(D);
- if (!Ctx)
+ if (!Ctx) {
Ctx = D->getDeclContext();
-
+
+ assert((!D->isTemplateParameter() || !Ctx->isTranslationUnit()) &&
+ "Template parameter doesn't have its context yet!");
+ }
+
while (!Ctx->isFileContext()) {
// Add template arguments from a class template instantiation.
if (ClassTemplateSpecializationDecl *Spec
@@ -446,10 +451,15 @@ void Sema::PrintInstantiationStack() {
Diags.Report(Active->PointOfInstantiation, DiagID)
<< Function
<< Active->InstantiationRange;
- } else {
+ } else if (VarDecl *VD = dyn_cast<VarDecl>(D)) {
Diags.Report(Active->PointOfInstantiation,
diag::note_template_static_data_member_def_here)
- << cast<VarDecl>(D)
+ << VD
+ << Active->InstantiationRange;
+ } else {
+ Diags.Report(Active->PointOfInstantiation,
+ diag::note_template_type_alias_instantiation_here)
+ << cast<TypeAliasTemplateDecl>(D)
<< Active->InstantiationRange;
}
break;
@@ -918,7 +928,8 @@ TemplateInstantiator::RebuildElaboratedType(SourceLocation KeywordLoc,
// like it's likely to produce a lot of spurious errors.
if (Keyword != ETK_None && Keyword != ETK_Typename) {
TagTypeKind Kind = TypeWithKeyword::getTagTypeKindForKeyword(Keyword);
- if (!SemaRef.isAcceptableTagRedeclaration(TD, Kind, TagLocation, *Id)) {
+ if (!SemaRef.isAcceptableTagRedeclaration(TD, Kind, /*isDefinition*/false,
+ TagLocation, *Id)) {
SemaRef.Diag(TagLocation, diag::err_use_with_wrong_tag)
<< Id
<< FixItHint::CreateReplacement(SourceRange(TagLocation),
@@ -968,8 +979,7 @@ TemplateName TemplateInstantiator::TransformTemplateName(CXXScopeSpec &SS,
}
TemplateName Template = Arg.getAsTemplate();
- assert(!Template.isNull() && Template.getAsTemplateDecl() &&
- "Wrong kind of template template argument");
+ assert(!Template.isNull() && "Null template template argument");
// We don't ever want to substitute for a qualified template name, since
// the qualifier is handled separately. So, look through the qualified
@@ -1384,6 +1394,12 @@ static bool NeedsInstantiationAsFunctionType(TypeSourceInfo *T) {
for (unsigned I = 0, E = FP.getNumArgs(); I != E; ++I) {
ParmVarDecl *P = FP.getArg(I);
+ // The parameter's type as written might be dependent even if the
+ // decayed type was not dependent.
+ if (TypeSourceInfo *TSInfo = P->getTypeSourceInfo())
+ if (TSInfo->getType()->isDependentType())
+ return true;
+
// TODO: currently we always rebuild expressions. When we
// properly get lazier about this, we should use the same
// logic to avoid rebuilding prototypes here.
@@ -1729,6 +1745,8 @@ Sema::InstantiateClass(SourceLocation PointOfInstantiation,
TemplateDeclInstantiator Instantiator(*this, Instantiation, TemplateArgs);
llvm::SmallVector<Decl*, 4> Fields;
+ llvm::SmallVector<std::pair<FieldDecl*, FieldDecl*>, 4>
+ FieldsWithMemberInitializers;
for (RecordDecl::decl_iterator Member = Pattern->decls_begin(),
MemberEnd = Pattern->decls_end();
Member != MemberEnd; ++Member) {
@@ -1751,9 +1769,13 @@ Sema::InstantiateClass(SourceLocation PointOfInstantiation,
Decl *NewMember = Instantiator.Visit(*Member);
if (NewMember) {
- if (FieldDecl *Field = dyn_cast<FieldDecl>(NewMember))
+ if (FieldDecl *Field = dyn_cast<FieldDecl>(NewMember)) {
Fields.push_back(Field);
- else if (NewMember->isInvalidDecl())
+ FieldDecl *OldField = cast<FieldDecl>(*Member);
+ if (OldField->getInClassInitializer())
+ FieldsWithMemberInitializers.push_back(std::make_pair(OldField,
+ Field));
+ } else if (NewMember->isInvalidDecl())
Invalid = true;
} else {
// FIXME: Eventually, a NULL return will mean that one of the
@@ -1767,6 +1789,43 @@ Sema::InstantiateClass(SourceLocation PointOfInstantiation,
Fields.data(), Fields.size(), SourceLocation(), SourceLocation(),
0);
CheckCompletedCXXClass(Instantiation);
+
+ // Attach any in-class member initializers now the class is complete.
+ for (unsigned I = 0, N = FieldsWithMemberInitializers.size(); I != N; ++I) {
+ FieldDecl *OldField = FieldsWithMemberInitializers[I].first;
+ FieldDecl *NewField = FieldsWithMemberInitializers[I].second;
+ Expr *OldInit = OldField->getInClassInitializer();
+ ExprResult NewInit = SubstExpr(OldInit, TemplateArgs);
+
+ // If the initialization is no longer dependent, check it now.
+ if ((OldField->getType()->isDependentType() || OldInit->isTypeDependent())
+ && !NewField->getType()->isDependentType()
+ && !NewInit.get()->isTypeDependent()) {
+ // FIXME: handle list-initialization
+ SourceLocation EqualLoc = NewField->getLocation();
+ NewInit = PerformCopyInitialization(
+ InitializedEntity::InitializeMember(NewField), EqualLoc,
+ NewInit.release());
+
+ if (!NewInit.isInvalid()) {
+ CheckImplicitConversions(NewInit.get(), EqualLoc);
+
+ // C++0x [class.base.init]p7:
+ // The initialization of each base and member constitutes a
+ // full-expression.
+ NewInit = MaybeCreateExprWithCleanups(NewInit);
+ }
+ }
+
+ if (NewInit.isInvalid())
+ NewField->setInvalidDecl();
+ else
+ NewField->setInClassInitializer(NewInit.release());
+ }
+
+ if (!FieldsWithMemberInitializers.empty())
+ ActOnFinishDelayedMemberInitializers(Instantiation);
+
if (Instantiation->isInvalidDecl())
Invalid = true;
else {
@@ -2009,7 +2068,7 @@ Sema::InstantiateClassMembers(SourceLocation PointOfInstantiation,
SuppressNew)
continue;
- if (Function->hasBody())
+ if (Function->isDefined())
continue;
if (TSK == TSK_ExplicitInstantiationDefinition) {
@@ -2019,7 +2078,7 @@ Sema::InstantiateClassMembers(SourceLocation PointOfInstantiation,
// specialization and is only an explicit instantiation definition
// of members whose definition is visible at the point of
// instantiation.
- if (!Pattern->hasBody())
+ if (!Pattern->isDefined())
continue;
Function->setTemplateSpecializationKind(TSK, PointOfInstantiation);
diff --git a/lib/Sema/SemaTemplateInstantiateDecl.cpp b/lib/Sema/SemaTemplateInstantiateDecl.cpp
index 6e11ef5..e78aa29 100644
--- a/lib/Sema/SemaTemplateInstantiateDecl.cpp
+++ b/lib/Sema/SemaTemplateInstantiateDecl.cpp
@@ -128,8 +128,8 @@ TemplateDeclInstantiator::VisitNamespaceAliasDecl(NamespaceAliasDecl *D) {
return Inst;
}
-Decl *TemplateDeclInstantiator::VisitTypedefNameDecl(TypedefNameDecl *D,
- bool IsTypeAlias) {
+Decl *TemplateDeclInstantiator::InstantiateTypedefNameDecl(TypedefNameDecl *D,
+ bool IsTypeAlias) {
bool Invalid = false;
TypeSourceInfo *DI = D->getTypeSourceInfo();
if (DI->getType()->isDependentType() ||
@@ -178,17 +178,62 @@ Decl *TemplateDeclInstantiator::VisitTypedefNameDecl(TypedefNameDecl *D,
SemaRef.InstantiateAttrs(TemplateArgs, D, Typedef);
Typedef->setAccess(D->getAccess());
- Owner->addDecl(Typedef);
return Typedef;
}
Decl *TemplateDeclInstantiator::VisitTypedefDecl(TypedefDecl *D) {
- return VisitTypedefNameDecl(D, /*IsTypeAlias=*/false);
+ Decl *Typedef = InstantiateTypedefNameDecl(D, /*IsTypeAlias=*/false);
+ Owner->addDecl(Typedef);
+ return Typedef;
}
Decl *TemplateDeclInstantiator::VisitTypeAliasDecl(TypeAliasDecl *D) {
- return VisitTypedefNameDecl(D, /*IsTypeAlias=*/true);
+ Decl *Typedef = InstantiateTypedefNameDecl(D, /*IsTypeAlias=*/true);
+ Owner->addDecl(Typedef);
+ return Typedef;
+}
+
+Decl *
+TemplateDeclInstantiator::VisitTypeAliasTemplateDecl(TypeAliasTemplateDecl *D) {
+ // Create a local instantiation scope for this type alias template, which
+ // will contain the instantiations of the template parameters.
+ LocalInstantiationScope Scope(SemaRef);
+
+ TemplateParameterList *TempParams = D->getTemplateParameters();
+ TemplateParameterList *InstParams = SubstTemplateParams(TempParams);
+ if (!InstParams)
+ return 0;
+
+ TypeAliasDecl *Pattern = D->getTemplatedDecl();
+
+ TypeAliasTemplateDecl *PrevAliasTemplate = 0;
+ if (Pattern->getPreviousDeclaration()) {
+ DeclContext::lookup_result Found = Owner->lookup(Pattern->getDeclName());
+ if (Found.first != Found.second) {
+ PrevAliasTemplate = dyn_cast<TypeAliasTemplateDecl>(*Found.first);
+ }
+ }
+
+ TypeAliasDecl *AliasInst = cast_or_null<TypeAliasDecl>(
+ InstantiateTypedefNameDecl(Pattern, /*IsTypeAlias=*/true));
+ if (!AliasInst)
+ return 0;
+
+ TypeAliasTemplateDecl *Inst
+ = TypeAliasTemplateDecl::Create(SemaRef.Context, Owner, D->getLocation(),
+ D->getDeclName(), InstParams, AliasInst);
+ if (PrevAliasTemplate)
+ Inst->setPreviousDeclaration(PrevAliasTemplate);
+
+ Inst->setAccess(D->getAccess());
+
+ if (!PrevAliasTemplate)
+ Inst->setInstantiatedFromMemberTemplate(D);
+
+ Owner->addDecl(Inst);
+
+ return Inst;
}
/// \brief Instantiate an initializer, breaking it into separate
@@ -432,6 +477,7 @@ Decl *TemplateDeclInstantiator::VisitFieldDecl(FieldDecl *D) {
D->getLocation(),
D->isMutable(),
BitWidth,
+ D->hasInClassInitializer(),
D->getTypeSpecStartLoc(),
D->getAccess(),
0);
@@ -1171,7 +1217,7 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl(FunctionDecl *D,
D->isThisDeclarationADefinition()) {
// Check for a function body.
const FunctionDecl *Definition = 0;
- if (Function->hasBody(Definition) &&
+ if (Function->isDefined(Definition) &&
Definition->getTemplateSpecializationKind() == TSK_Undeclared) {
SemaRef.Diag(Function->getLocation(), diag::err_redefinition)
<< Function->getDeclName();
@@ -1203,7 +1249,7 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl(FunctionDecl *D,
default:
if (const FunctionDecl *RPattern
= R->getTemplateInstantiationPattern())
- if (RPattern->hasBody(RPattern)) {
+ if (RPattern->isDefined(RPattern)) {
SemaRef.Diag(Function->getLocation(), diag::err_redefinition)
<< Function->getDeclName();
SemaRef.Diag(R->getLocation(), diag::note_previous_definition);
@@ -1219,6 +1265,7 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl(FunctionDecl *D,
PrincipalDecl->isInIdentifierNamespace(Decl::IDNS_Ordinary))
PrincipalDecl->setNonMemberOperator();
+ assert(!D->isDefaulted() && "only methods should be defaulted");
return Function;
}
@@ -1451,7 +1498,14 @@ TemplateDeclInstantiator::VisitCXXMethodDecl(CXXMethodDecl *D,
else
Owner->addDecl(DeclToAdd);
}
-
+
+ if (D->isExplicitlyDefaulted()) {
+ SemaRef.SetDeclDefaulted(Method, Method->getLocation());
+ } else {
+ assert(!D->isDefaulted() &&
+ "should not implicitly default uninstantiated function");
+ }
+
return Method;
}
@@ -2079,8 +2133,8 @@ TemplateDeclInstantiator::SubstFunctionType(FunctionDecl *D,
bool
TemplateDeclInstantiator::InitFunctionInstantiation(FunctionDecl *New,
FunctionDecl *Tmpl) {
- if (Tmpl->isDeleted())
- New->setDeleted();
+ if (Tmpl->isDeletedAsWritten())
+ New->setDeletedAsWritten();
// If we are performing substituting explicitly-specified template arguments
// or deduced template arguments into a function template and we reach this
@@ -2186,6 +2240,7 @@ TemplateDeclInstantiator::InitFunctionInstantiation(FunctionDecl *New,
}
Expr *NoexceptExpr = 0;
if (Expr *OldNoexceptExpr = Proto->getNoexceptExpr()) {
+ EnterExpressionEvaluationContext Unevaluated(SemaRef, Sema::Unevaluated);
ExprResult E = SemaRef.SubstExpr(OldNoexceptExpr, TemplateArgs);
if (E.isUsable())
NoexceptExpr = E.take();
@@ -2255,7 +2310,7 @@ void Sema::InstantiateFunctionDefinition(SourceLocation PointOfInstantiation,
FunctionDecl *Function,
bool Recursive,
bool DefinitionRequired) {
- if (Function->isInvalidDecl() || Function->hasBody())
+ if (Function->isInvalidDecl() || Function->isDefined())
return;
// Never instantiate an explicit specialization.
@@ -2264,12 +2319,19 @@ void Sema::InstantiateFunctionDefinition(SourceLocation PointOfInstantiation,
// Find the function body that we'll be substituting.
const FunctionDecl *PatternDecl = Function->getTemplateInstantiationPattern();
- Stmt *Pattern = 0;
- if (PatternDecl)
- Pattern = PatternDecl->getBody(PatternDecl);
+ assert(PatternDecl && "instantiating a non-template");
+
+ Stmt *Pattern = PatternDecl->getBody(PatternDecl);
+ assert(PatternDecl && "template definition is not a template");
+ if (!Pattern) {
+ // Try to find a defaulted definition
+ PatternDecl->isDefined(PatternDecl);
+ }
+ assert(PatternDecl && "template definition is not a template");
// Postpone late parsed template instantiations.
- if (PatternDecl->isLateTemplateParsed() && !LateTemplateParser) {
+ if (PatternDecl->isLateTemplateParsed() &&
+ !LateTemplateParser) {
PendingInstantiations.push_back(
std::make_pair(Function, PointOfInstantiation));
return;
@@ -2277,13 +2339,13 @@ void Sema::InstantiateFunctionDefinition(SourceLocation PointOfInstantiation,
// Call the LateTemplateParser callback if there a need to late parse
// a templated function definition.
- if (!Pattern && PatternDecl && PatternDecl->isLateTemplateParsed() &&
+ if (!Pattern && PatternDecl->isLateTemplateParsed() &&
LateTemplateParser) {
LateTemplateParser(OpaqueParser, PatternDecl);
Pattern = PatternDecl->getBody(PatternDecl);
}
- if (!Pattern) {
+ if (!Pattern && !PatternDecl->isDefaulted()) {
if (DefinitionRequired) {
if (Function->getPrimaryTemplate())
Diag(PointOfInstantiation,
@@ -2378,21 +2440,27 @@ void Sema::InstantiateFunctionDefinition(SourceLocation PointOfInstantiation,
MultiLevelTemplateArgumentList TemplateArgs =
getTemplateInstantiationArgs(Function, 0, false, PatternDecl);
- // If this is a constructor, instantiate the member initializers.
- if (const CXXConstructorDecl *Ctor =
- dyn_cast<CXXConstructorDecl>(PatternDecl)) {
- InstantiateMemInitializers(cast<CXXConstructorDecl>(Function), Ctor,
- TemplateArgs);
- }
+ if (PatternDecl->isDefaulted()) {
+ ActOnFinishFunctionBody(Function, 0, /*IsInstantiation=*/true);
- // Instantiate the function body.
- StmtResult Body = SubstStmt(Pattern, TemplateArgs);
+ SetDeclDefaulted(Function, PatternDecl->getLocation());
+ } else {
+ // If this is a constructor, instantiate the member initializers.
+ if (const CXXConstructorDecl *Ctor =
+ dyn_cast<CXXConstructorDecl>(PatternDecl)) {
+ InstantiateMemInitializers(cast<CXXConstructorDecl>(Function), Ctor,
+ TemplateArgs);
+ }
- if (Body.isInvalid())
- Function->setInvalidDecl();
-
- ActOnFinishFunctionBody(Function, Body.get(),
- /*IsInstantiation=*/true);
+ // Instantiate the function body.
+ StmtResult Body = SubstStmt(Pattern, TemplateArgs);
+
+ if (Body.isInvalid())
+ Function->setInvalidDecl();
+
+ ActOnFinishFunctionBody(Function, Body.get(),
+ /*IsInstantiation=*/true);
+ }
PerformDependentDiagnostics(PatternDecl, TemplateArgs);
@@ -2415,9 +2483,13 @@ void Sema::InstantiateFunctionDefinition(SourceLocation PointOfInstantiation,
PerformPendingInstantiations();
// Restore the set of pending vtables.
+ assert(VTableUses.empty() &&
+ "VTableUses should be empty before it is discarded.");
VTableUses.swap(SavedVTableUses);
// Restore the set of pending implicit instantiations.
+ assert(PendingInstantiations.empty() &&
+ "PendingInstantiations should be empty before it is discarded.");
PendingInstantiations.swap(SavedPendingInstantiations);
}
}
@@ -2484,6 +2556,10 @@ void Sema::InstantiateStaticDataMemberDefinition(
== TSK_ExplicitInstantiationDeclaration)
return;
+ // If we already have a definition, we're done.
+ if (Var->getDefinition())
+ return;
+
InstantiatingTemplate Inst(*this, PointOfInstantiation, Var);
if (Inst)
return;
@@ -2491,9 +2567,12 @@ void Sema::InstantiateStaticDataMemberDefinition(
// If we're performing recursive template instantiation, create our own
// queue of pending implicit instantiations that we will instantiate later,
// while we're still within our own instantiation context.
+ llvm::SmallVector<VTableUse, 16> SavedVTableUses;
std::deque<PendingImplicitInstantiation> SavedPendingInstantiations;
- if (Recursive)
+ if (Recursive) {
+ VTableUses.swap(SavedVTableUses);
PendingInstantiations.swap(SavedPendingInstantiations);
+ }
// Enter the scope of this instantiation. We don't use
// PushDeclContext because we don't have a scope.
@@ -2515,11 +2594,23 @@ void Sema::InstantiateStaticDataMemberDefinition(
}
if (Recursive) {
+ // Define any newly required vtables.
+ DefineUsedVTables();
+
// Instantiate any pending implicit instantiations found during the
// instantiation of this template.
PerformPendingInstantiations();
+ // Restore the set of pending vtables.
+ assert(VTableUses.empty() &&
+ "VTableUses should be empty before it is discarded, "
+ "while instantiating static data member.");
+ VTableUses.swap(SavedVTableUses);
+
// Restore the set of pending implicit instantiations.
+ assert(PendingInstantiations.empty() &&
+ "PendingInstantiations should be empty before it is discarded, "
+ "while instantiating static data member.");
PendingInstantiations.swap(SavedPendingInstantiations);
}
}
@@ -3115,10 +3206,7 @@ NamedDecl *Sema::FindInstantiatedDecl(SourceLocation Loc, NamedDecl *D,
/// \brief Performs template instantiation for all implicit template
/// instantiations we have seen until this point.
-///
-/// \returns true if anything was instantiated.
-bool Sema::PerformPendingInstantiations(bool LocalOnly) {
- bool InstantiatedAnything = false;
+void Sema::PerformPendingInstantiations(bool LocalOnly) {
while (!PendingLocalImplicitInstantiations.empty() ||
(!LocalOnly && !PendingInstantiations.empty())) {
PendingImplicitInstantiation Inst;
@@ -3139,7 +3227,6 @@ bool Sema::PerformPendingInstantiations(bool LocalOnly) {
TSK_ExplicitInstantiationDefinition;
InstantiateFunctionDefinition(/*FIXME:*/Inst.second, Function, true,
DefinitionRequired);
- InstantiatedAnything = true;
continue;
}
@@ -3176,10 +3263,7 @@ bool Sema::PerformPendingInstantiations(bool LocalOnly) {
TSK_ExplicitInstantiationDefinition;
InstantiateStaticDataMemberDefinition(/*FIXME:*/Inst.second, Var, true,
DefinitionRequired);
- InstantiatedAnything = true;
}
-
- return InstantiatedAnything;
}
void Sema::PerformDependentDiagnostics(const DeclContext *Pattern,
diff --git a/lib/Sema/SemaTemplateVariadic.cpp b/lib/Sema/SemaTemplateVariadic.cpp
index 096d353..86d3bc1 100644
--- a/lib/Sema/SemaTemplateVariadic.cpp
+++ b/lib/Sema/SemaTemplateVariadic.cpp
@@ -617,7 +617,8 @@ bool Sema::containsUnexpandedParameterPacks(Declarator &D) {
const DeclSpec &DS = D.getDeclSpec();
switch (DS.getTypeSpecType()) {
case TST_typename:
- case TST_typeofType: {
+ case TST_typeofType:
+ case TST_underlyingType: {
QualType T = DS.getRepAsType().get();
if (!T.isNull() && T->containsUnexpandedParameterPack())
return true;
diff --git a/lib/Sema/SemaType.cpp b/lib/Sema/SemaType.cpp
index 00ac1d6..5fd8afa 100644
--- a/lib/Sema/SemaType.cpp
+++ b/lib/Sema/SemaType.cpp
@@ -15,6 +15,7 @@
#include "clang/Sema/Template.h"
#include "clang/Basic/OpenCL.h"
#include "clang/AST/ASTContext.h"
+#include "clang/AST/ASTMutationListener.h"
#include "clang/AST/CXXInheritance.h"
#include "clang/AST/DeclObjC.h"
#include "clang/AST/DeclTemplate.h"
@@ -836,6 +837,18 @@ static QualType ConvertDeclSpecToType(Sema &S, TypeProcessingState &state) {
}
break;
}
+ case DeclSpec::TST_underlyingType:
+ Result = S.GetTypeFromParser(DS.getRepAsType());
+ assert(!Result.isNull() && "Didn't get a type for __underlying_type?");
+ Result = S.BuildUnaryTransformType(Result,
+ UnaryTransformType::EnumUnderlyingType,
+ DS.getTypeSpecTypeLoc());
+ if (Result.isNull()) {
+ Result = Context.IntTy;
+ declarator.setInvalidType(true);
+ }
+ break;
+
case DeclSpec::TST_auto: {
// TypeQuals handled by caller.
Result = Context.getAutoType(QualType());
@@ -1048,6 +1061,9 @@ QualType Sema::BuildPointerType(QualType T,
QualType Sema::BuildReferenceType(QualType T, bool SpelledAsLValue,
SourceLocation Loc,
DeclarationName Entity) {
+ assert(Context.getCanonicalType(T) != Context.OverloadTy &&
+ "Unresolved overloaded function type");
+
// C++0x [dcl.ref]p6:
// If a typedef (7.1.3), a type template-parameter (14.3.1), or a
// decltype-specifier (7.1.6.2) denotes a type TR that is a reference to a
@@ -1464,41 +1480,37 @@ static void DiagnoseIgnoredQualifiers(unsigned Quals,
FixItHint VolatileFixIt;
FixItHint RestrictFixIt;
+ const SourceManager &SM = S.getSourceManager();
+
// FIXME: The locations here are set kind of arbitrarily. It'd be nicer to
// find a range and grow it to encompass all the qualifiers, regardless of
// the order in which they textually appear.
if (Quals & Qualifiers::Const) {
ConstFixIt = FixItHint::CreateRemoval(ConstQualLoc);
- Loc = ConstQualLoc;
- ++NumQuals;
QualStr = "const";
+ ++NumQuals;
+ if (!Loc.isValid() || SM.isBeforeInTranslationUnit(ConstQualLoc, Loc))
+ Loc = ConstQualLoc;
}
if (Quals & Qualifiers::Volatile) {
VolatileFixIt = FixItHint::CreateRemoval(VolatileQualLoc);
- if (NumQuals == 0) {
- Loc = VolatileQualLoc;
- QualStr = "volatile";
- } else {
- QualStr += " volatile";
- }
+ QualStr += (NumQuals == 0 ? "volatile" : " volatile");
++NumQuals;
+ if (!Loc.isValid() || SM.isBeforeInTranslationUnit(VolatileQualLoc, Loc))
+ Loc = VolatileQualLoc;
}
if (Quals & Qualifiers::Restrict) {
RestrictFixIt = FixItHint::CreateRemoval(RestrictQualLoc);
- if (NumQuals == 0) {
- Loc = RestrictQualLoc;
- QualStr = "restrict";
- } else {
- QualStr += " restrict";
- }
+ QualStr += (NumQuals == 0 ? "restrict" : " restrict");
++NumQuals;
+ if (!Loc.isValid() || SM.isBeforeInTranslationUnit(RestrictQualLoc, Loc))
+ Loc = RestrictQualLoc;
}
assert(NumQuals > 0 && "No known qualifiers?");
S.Diag(Loc, diag::warn_qual_return_type)
- << QualStr << NumQuals
- << ConstFixIt << VolatileFixIt << RestrictFixIt;
+ << QualStr << NumQuals << ConstFixIt << VolatileFixIt << RestrictFixIt;
}
/// GetTypeForDeclarator - Convert the type for the specified
@@ -1581,6 +1593,8 @@ TypeSourceInfo *Sema::GetTypeForDeclarator(Declarator &D, Scope *S,
Error = 0; // Function prototype
break;
case Declarator::MemberContext:
+ if (D.getDeclSpec().getStorageClassSpec() == DeclSpec::SCS_static)
+ break;
switch (cast<TagDecl>(CurContext)->getTagKind()) {
case TTK_Enum: assert(0 && "unhandled tag kind"); break;
case TTK_Struct: Error = 1; /* Struct member */ break;
@@ -1601,6 +1615,7 @@ TypeSourceInfo *Sema::GetTypeForDeclarator(Declarator &D, Scope *S,
Error = 7; // Template type argument
break;
case Declarator::AliasDeclContext:
+ case Declarator::AliasTemplateContext:
Error = 9; // Type alias
break;
case Declarator::TypeNameContext:
@@ -1659,7 +1674,8 @@ TypeSourceInfo *Sema::GetTypeForDeclarator(Declarator &D, Scope *S,
// Does this declaration declare a typedef-name?
bool IsTypedefName =
D.getDeclSpec().getStorageClassSpec() == DeclSpec::SCS_typedef ||
- D.getContext() == Declarator::AliasDeclContext;
+ D.getContext() == Declarator::AliasDeclContext ||
+ D.getContext() == Declarator::AliasTemplateContext;
// Walk the DeclTypeInfo, building the recursive type as we go.
// DeclTypeInfos are ordered from the identifier out, which is
@@ -1839,7 +1855,8 @@ TypeSourceInfo *Sema::GetTypeForDeclarator(Declarator &D, Scope *S,
// anyway.
if (IsTypedefName && FTI.getExceptionSpecType())
Diag(FTI.getExceptionSpecLoc(), diag::err_exception_spec_in_typedef)
- << (D.getContext() == Declarator::AliasDeclContext);
+ << (D.getContext() == Declarator::AliasDeclContext ||
+ D.getContext() == Declarator::AliasTemplateContext);
if (!FTI.NumArgs && !FTI.isVariadic && !getLangOptions().CPlusPlus) {
// Simple void foo(), where the incoming T is the result type.
@@ -2204,6 +2221,7 @@ TypeSourceInfo *Sema::GetTypeForDeclarator(Declarator &D, Scope *S,
case Declarator::ObjCPrototypeContext: // FIXME: special diagnostic here?
case Declarator::TypeNameContext:
case Declarator::AliasDeclContext:
+ case Declarator::AliasTemplateContext:
case Declarator::MemberContext:
case Declarator::BlockContext:
case Declarator::ForContext:
@@ -2367,6 +2385,16 @@ namespace {
Sema::GetTypeFromParser(DS.getRepAsType(), &TInfo);
TL.setUnderlyingTInfo(TInfo);
}
+ void VisitUnaryTransformTypeLoc(UnaryTransformTypeLoc TL) {
+ // FIXME: This holds only because we only have one unary transform.
+ assert(DS.getTypeSpecType() == DeclSpec::TST_underlyingType);
+ TL.setKWLoc(DS.getTypeSpecTypeLoc());
+ TL.setParensRange(DS.getTypeofParensRange());
+ assert(DS.getRepAsType());
+ TypeSourceInfo *TInfo = 0;
+ Sema::GetTypeFromParser(DS.getRepAsType(), &TInfo);
+ TL.setUnderlyingTInfo(TInfo);
+ }
void VisitBuiltinTypeLoc(BuiltinTypeLoc TL) {
// By default, use the source location of the type specifier.
TL.setBuiltinLoc(DS.getTypeSpecTypeLoc());
@@ -2640,13 +2668,17 @@ TypeResult Sema::ActOnTypeName(Scope *S, Declarator &D) {
CheckExtraCXXDefaultArguments(D);
// C++0x [dcl.type]p3:
- // A type-specifier-seq shall not define a class or enumeration
- // unless it appears in the type-id of an alias-declaration
- // (7.1.3).
- if (OwnedTag && OwnedTag->isDefinition() &&
- D.getContext() != Declarator::AliasDeclContext)
- Diag(OwnedTag->getLocation(), diag::err_type_defined_in_type_specifier)
- << Context.getTypeDeclType(OwnedTag);
+ // A type-specifier-seq shall not define a class or enumeration unless
+ // it appears in the type-id of an alias-declaration (7.1.3) that is not
+ // the declaration of a template-declaration.
+ if (OwnedTag && OwnedTag->isDefinition()) {
+ if (D.getContext() == Declarator::AliasTemplateContext)
+ Diag(OwnedTag->getLocation(), diag::err_type_defined_in_alias_template)
+ << Context.getTypeDeclType(OwnedTag);
+ else if (D.getContext() != Declarator::AliasDeclContext)
+ Diag(OwnedTag->getLocation(), diag::err_type_defined_in_type_specifier)
+ << Context.getTypeDeclType(OwnedTag);
+ }
}
return CreateParsedType(T, TInfo);
@@ -3213,6 +3245,82 @@ static void processTypeAttrs(TypeProcessingState &state, QualType &type,
} while ((attrs = next));
}
+/// \brief Ensure that the type of the given expression is complete.
+///
+/// This routine checks whether the expression \p E has a complete type. If the
+/// expression refers to an instantiable construct, that instantiation is
+/// performed as needed to complete its type. Furthermore
+/// Sema::RequireCompleteType is called for the expression's type (or in the
+/// case of a reference type, the referred-to type).
+///
+/// \param E The expression whose type is required to be complete.
+/// \param PD The partial diagnostic that will be printed out if the type cannot
+/// be completed.
+///
+/// \returns \c true if the type of \p E is incomplete and diagnosed, \c false
+/// otherwise.
+bool Sema::RequireCompleteExprType(Expr *E, const PartialDiagnostic &PD,
+ std::pair<SourceLocation,
+ PartialDiagnostic> Note) {
+ QualType T = E->getType();
+
+ // Fast path the case where the type is already complete.
+ if (!T->isIncompleteType())
+ return false;
+
+ // Incomplete array types may be completed by the initializer attached to
+ // their definitions. For static data members of class templates we need to
+ // instantiate the definition to get this initializer and complete the type.
+ if (T->isIncompleteArrayType()) {
+ if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E->IgnoreParens())) {
+ if (VarDecl *Var = dyn_cast<VarDecl>(DRE->getDecl())) {
+ if (Var->isStaticDataMember() &&
+ Var->getInstantiatedFromStaticDataMember()) {
+
+ MemberSpecializationInfo *MSInfo = Var->getMemberSpecializationInfo();
+ assert(MSInfo && "Missing member specialization information?");
+ if (MSInfo->getTemplateSpecializationKind()
+ != TSK_ExplicitSpecialization) {
+ // If we don't already have a point of instantiation, this is it.
+ if (MSInfo->getPointOfInstantiation().isInvalid()) {
+ MSInfo->setPointOfInstantiation(E->getLocStart());
+
+ // This is a modification of an existing AST node. Notify
+ // listeners.
+ if (ASTMutationListener *L = getASTMutationListener())
+ L->StaticDataMemberInstantiated(Var);
+ }
+
+ InstantiateStaticDataMemberDefinition(E->getExprLoc(), Var);
+
+ // Update the type to the newly instantiated definition's type both
+ // here and within the expression.
+ if (VarDecl *Def = Var->getDefinition()) {
+ DRE->setDecl(Def);
+ T = Def->getType();
+ DRE->setType(T);
+ E->setType(T);
+ }
+ }
+
+ // We still go on to try to complete the type independently, as it
+ // may also require instantiations or diagnostics if it remains
+ // incomplete.
+ }
+ }
+ }
+ }
+
+ // FIXME: Are there other cases which require instantiating something other
+ // than the type to complete the type of an expression?
+
+ // Look through reference types and complete the referred type.
+ if (const ReferenceType *Ref = T->getAs<ReferenceType>())
+ T = Ref->getPointeeType();
+
+ return RequireCompleteType(E->getExprLoc(), T, PD, Note);
+}
+
/// @brief Ensure that the type T is a complete type.
///
/// This routine checks whether the type @p T is complete in any
@@ -3363,3 +3471,27 @@ QualType Sema::BuildDecltypeType(Expr *E, SourceLocation Loc) {
return Context.getDecltypeType(E);
}
+
+QualType Sema::BuildUnaryTransformType(QualType BaseType,
+ UnaryTransformType::UTTKind UKind,
+ SourceLocation Loc) {
+ switch (UKind) {
+ case UnaryTransformType::EnumUnderlyingType:
+ if (!BaseType->isDependentType() && !BaseType->isEnumeralType()) {
+ Diag(Loc, diag::err_only_enums_have_underlying_types);
+ return QualType();
+ } else {
+ QualType Underlying = BaseType;
+ if (!BaseType->isDependentType()) {
+ EnumDecl *ED = BaseType->getAs<EnumType>()->getDecl();
+ assert(ED && "EnumType has no EnumDecl");
+ DiagnoseUseOfDecl(ED, Loc);
+ Underlying = ED->getIntegerType();
+ }
+ assert(!Underlying.isNull());
+ return Context.getUnaryTransformType(BaseType, Underlying,
+ UnaryTransformType::EnumUnderlyingType);
+ }
+ }
+ llvm_unreachable("unknown unary transform type");
+}
diff --git a/lib/Sema/TreeTransform.h b/lib/Sema/TreeTransform.h
index 2a71e14..ff2e46a 100644
--- a/lib/Sema/TreeTransform.h
+++ b/lib/Sema/TreeTransform.h
@@ -21,6 +21,7 @@
#include "clang/Sema/ScopeInfo.h"
#include "clang/AST/Decl.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"
@@ -701,6 +702,11 @@ public:
/// By default, builds a new TypeOfType with the given underlying type.
QualType RebuildTypeOfType(QualType Underlying);
+ /// \brief Build a new unary transform type.
+ QualType RebuildUnaryTransformType(QualType BaseType,
+ UnaryTransformType::UTTKind UKind,
+ SourceLocation Loc);
+
/// \brief Build a new C++0x decltype type.
///
/// By default, performs semantic analysis when building the decltype type.
@@ -855,7 +861,7 @@ public:
case LookupResult::Found:
case LookupResult::FoundOverloaded:
case LookupResult::FoundUnresolvedValue: {
- NamedDecl *SomeDecl = Result.getRepresentativeDecl();
+ NamedDecl *SomeDecl = Result.getRepresentativeDecl();
unsigned Kind = 0;
if (isa<TypedefDecl>(SomeDecl)) Kind = 1;
else if (isa<TypeAliasDecl>(SomeDecl)) Kind = 2;
@@ -863,7 +869,7 @@ public:
SemaRef.Diag(IdLoc, diag::err_tag_reference_non_tag) << Kind;
SemaRef.Diag(SomeDecl->getLocation(), diag::note_declared_at);
break;
- }
+ }
default:
// FIXME: Would be nice to highlight just the source range.
SemaRef.Diag(IdLoc, diag::err_not_tag_in_scope)
@@ -873,7 +879,8 @@ public:
return QualType();
}
- if (!SemaRef.isAcceptableTagRedeclaration(Tag, Kind, IdLoc, *Id)) {
+ if (!SemaRef.isAcceptableTagRedeclaration(Tag, Kind, /*isDefinition*/false,
+ IdLoc, *Id)) {
SemaRef.Diag(KeywordLoc, diag::err_use_with_wrong_tag) << Id;
SemaRef.Diag(Tag->getLocation(), diag::note_previous_use);
return QualType();
@@ -1372,7 +1379,7 @@ public:
UnaryExprOrTypeTrait ExprKind,
SourceRange R) {
ExprResult Result
- = getSema().CreateUnaryExprOrTypeTraitExpr(SubExpr, OpLoc, ExprKind, R);
+ = getSema().CreateUnaryExprOrTypeTraitExpr(SubExpr, OpLoc, ExprKind);
if (Result.isInvalid())
return ExprError();
@@ -2567,9 +2574,13 @@ TreeTransform<Derived>::TransformNestedNameSpecifierLoc(
Q.getLocalEndLoc());
break;
}
-
- SemaRef.Diag(TL.getBeginLoc(), diag::err_nested_name_spec_non_tag)
- << TL.getType() << SS.getRange();
+ // If the nested-name-specifier is an invalid type def, don't emit an
+ // error because a previous error should have already been emitted.
+ TypedefTypeLoc* TTL = dyn_cast<TypedefTypeLoc>(&TL);
+ if (!TTL || !TTL->getTypedefNameDecl()->isInvalidDecl()) {
+ SemaRef.Diag(TL.getBeginLoc(), diag::err_nested_name_spec_non_tag)
+ << TL.getType() << SS.getRange();
+ }
return NestedNameSpecifierLoc();
}
}
@@ -4154,6 +4165,29 @@ QualType TreeTransform<Derived>::TransformDecltypeType(TypeLocBuilder &TLB,
}
template<typename Derived>
+QualType TreeTransform<Derived>::TransformUnaryTransformType(
+ TypeLocBuilder &TLB,
+ UnaryTransformTypeLoc TL) {
+ QualType Result = TL.getType();
+ if (Result->isDependentType()) {
+ const UnaryTransformType *T = TL.getTypePtr();
+ QualType NewBase =
+ getDerived().TransformType(TL.getUnderlyingTInfo())->getType();
+ Result = getDerived().RebuildUnaryTransformType(NewBase,
+ T->getUTTKind(),
+ TL.getKWLoc());
+ if (Result.isNull())
+ return QualType();
+ }
+
+ UnaryTransformTypeLoc NewTL = TLB.push<UnaryTransformTypeLoc>(Result);
+ NewTL.setKWLoc(TL.getKWLoc());
+ NewTL.setParensRange(TL.getParensRange());
+ NewTL.setUnderlyingTInfo(TL.getUnderlyingTInfo());
+ return Result;
+}
+
+template<typename Derived>
QualType TreeTransform<Derived>::TransformAutoType(TypeLocBuilder &TLB,
AutoTypeLoc TL) {
const AutoType *T = TL.getTypePtr();
@@ -4389,6 +4423,23 @@ QualType TreeTransform<Derived>::TransformTemplateSpecializationType(
NewTemplateArgs);
if (!Result.isNull()) {
+ // Specializations of template template parameters are represented as
+ // TemplateSpecializationTypes, and substitution of type alias templates
+ // within a dependent context can transform them into
+ // DependentTemplateSpecializationTypes.
+ if (isa<DependentTemplateSpecializationType>(Result)) {
+ DependentTemplateSpecializationTypeLoc NewTL
+ = TLB.push<DependentTemplateSpecializationTypeLoc>(Result);
+ NewTL.setKeywordLoc(TL.getTemplateNameLoc());
+ NewTL.setQualifierLoc(NestedNameSpecifierLoc());
+ NewTL.setNameLoc(TL.getTemplateNameLoc());
+ NewTL.setLAngleLoc(TL.getLAngleLoc());
+ NewTL.setRAngleLoc(TL.getRAngleLoc());
+ for (unsigned i = 0, e = NewTemplateArgs.size(); i != e; ++i)
+ NewTL.setArgLocInfo(i, NewTemplateArgs[i].getLocInfo());
+ return Result;
+ }
+
TemplateSpecializationTypeLoc NewTL
= TLB.push<TemplateSpecializationTypeLoc>(Result);
NewTL.setTemplateNameLoc(TL.getTemplateNameLoc());
@@ -4478,6 +4529,23 @@ TreeTransform<Derived>::TransformElaboratedType(TypeLocBuilder &TLB,
if (NamedT.isNull())
return QualType();
+ // C++0x [dcl.type.elab]p2:
+ // If the identifier resolves to a typedef-name or the simple-template-id
+ // resolves to an alias template specialization, the
+ // elaborated-type-specifier is ill-formed.
+ if (T->getKeyword() != ETK_None && T->getKeyword() != ETK_Typename) {
+ if (const TemplateSpecializationType *TST =
+ NamedT->getAs<TemplateSpecializationType>()) {
+ TemplateName Template = TST->getTemplateName();
+ if (TypeAliasTemplateDecl *TAT =
+ dyn_cast_or_null<TypeAliasTemplateDecl>(Template.getAsTemplateDecl())) {
+ SemaRef.Diag(TL.getNamedTypeLoc().getBeginLoc(),
+ diag::err_tag_reference_non_tag) << 4;
+ SemaRef.Diag(TAT->getLocation(), diag::note_declared_at);
+ }
+ }
+ }
+
QualType Result = TL.getType();
if (getDerived().AlwaysRebuild() ||
QualifierLoc != TL.getQualifierLoc() ||
@@ -6629,8 +6697,12 @@ template<typename Derived>
ExprResult
TreeTransform<Derived>::TransformCXXThisExpr(CXXThisExpr *E) {
DeclContext *DC = getSema().getFunctionLevelDeclContext();
- CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(DC);
- QualType T = MD->getThisType(getSema().Context);
+ QualType T;
+ if (CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(DC))
+ T = MD->getThisType(getSema().Context);
+ else
+ T = getSema().Context.getPointerType(
+ getSema().Context.getRecordType(cast<CXXRecordDecl>(DC)));
if (!getDerived().AlwaysRebuild() && T == E->getType())
return SemaRef.Owned(E);
@@ -7449,6 +7521,7 @@ TreeTransform<Derived>::TransformUnresolvedMemberExpr(UnresolvedMemberExpr *Old)
template<typename Derived>
ExprResult
TreeTransform<Derived>::TransformCXXNoexceptExpr(CXXNoexceptExpr *E) {
+ EnterExpressionEvaluationContext Unevaluated(SemaRef, Sema::Unevaluated);
ExprResult SubExpr = getDerived().TransformExpr(E->getOperand());
if (SubExpr.isInvalid())
return ExprError();
@@ -7700,6 +7773,11 @@ TreeTransform<Derived>::TransformBlockExpr(BlockExpr *E) {
BlockScopeInfo *blockScope = SemaRef.getCurBlock();
blockScope->TheDecl->setIsVariadic(oldBlock->isVariadic());
+ // We built a new blockScopeInfo in call to ActOnBlockStart
+ // in above, CapturesCXXThis need be set here from the block
+ // expression.
+ blockScope->CapturesCXXThis = oldBlock->capturesCXXThis();
+
llvm::SmallVector<ParmVarDecl*, 4> params;
llvm::SmallVector<QualType, 4> paramTypes;
@@ -7759,22 +7837,21 @@ TreeTransform<Derived>::TransformBlockExpr(BlockExpr *E) {
#ifndef NDEBUG
// In builds with assertions, make sure that we captured everything we
// captured before.
+ if (!SemaRef.getDiagnostics().hasErrorOccurred()) {
+ for (BlockDecl::capture_iterator i = oldBlock->capture_begin(),
+ e = oldBlock->capture_end(); i != e; ++i) {
+ VarDecl *oldCapture = i->getVariable();
+
+ // Ignore parameter packs.
+ if (isa<ParmVarDecl>(oldCapture) &&
+ cast<ParmVarDecl>(oldCapture)->isParameterPack())
+ continue;
- if (oldBlock->capturesCXXThis()) assert(blockScope->CapturesCXXThis);
-
- for (BlockDecl::capture_iterator i = oldBlock->capture_begin(),
- e = oldBlock->capture_end(); i != e; ++i) {
- VarDecl *oldCapture = i->getVariable();
-
- // Ignore parameter packs.
- if (isa<ParmVarDecl>(oldCapture) &&
- cast<ParmVarDecl>(oldCapture)->isParameterPack())
- continue;
-
- VarDecl *newCapture =
- cast<VarDecl>(getDerived().TransformDecl(E->getCaretLocation(),
- oldCapture));
- assert(blockScope->CaptureMap.count(newCapture));
+ VarDecl *newCapture =
+ cast<VarDecl>(getDerived().TransformDecl(E->getCaretLocation(),
+ oldCapture));
+ assert(blockScope->CaptureMap.count(newCapture));
+ }
}
#endif
@@ -7805,6 +7882,13 @@ TreeTransform<Derived>::TransformBlockDeclRefExpr(BlockDeclRefExpr *E) {
ND, NameInfo, 0);
}
+template<typename Derived>
+ExprResult
+TreeTransform<Derived>::TransformAsTypeExpr(AsTypeExpr *E) {
+ assert(false && "Cannot transform asType expressions yet");
+ return SemaRef.Owned(E);
+}
+
//===----------------------------------------------------------------------===//
// Type reconstruction
//===----------------------------------------------------------------------===//
@@ -8010,6 +8094,13 @@ QualType TreeTransform<Derived>::RebuildDecltypeType(Expr *E,
}
template<typename Derived>
+QualType TreeTransform<Derived>::RebuildUnaryTransformType(QualType BaseType,
+ UnaryTransformType::UTTKind UKind,
+ SourceLocation Loc) {
+ return SemaRef.BuildUnaryTransformType(BaseType, UKind, Loc);
+}
+
+template<typename Derived>
QualType TreeTransform<Derived>::RebuildTemplateSpecializationType(
TemplateName Template,
SourceLocation TemplateNameLoc,
diff --git a/lib/Serialization/ASTReader.cpp b/lib/Serialization/ASTReader.cpp
index d2e41a9..8fb20d2 100644
--- a/lib/Serialization/ASTReader.cpp
+++ b/lib/Serialization/ASTReader.cpp
@@ -92,6 +92,7 @@ PCHValidator::ReadLanguageOptions(const LangOptions &LangOpts) {
PARSE_LANGOPT_IMPORTANT(AppleKext, diag::warn_pch_apple_kext);
PARSE_LANGOPT_IMPORTANT(ObjCDefaultSynthProperties,
diag::warn_pch_objc_auto_properties);
+ PARSE_LANGOPT_BENIGN(ObjCInferRelatedResultType)
PARSE_LANGOPT_IMPORTANT(NoConstantCFStrings,
diag::warn_pch_no_constant_cfstrings);
PARSE_LANGOPT_BENIGN(PascalStrings);
@@ -1697,7 +1698,8 @@ namespace {
using namespace clang::io;
HeaderFileInfo HFI;
unsigned Flags = *d++;
- HFI.isImport = (Flags >> 3) & 0x01;
+ HFI.isImport = (Flags >> 4) & 0x01;
+ HFI.isPragmaOnce = (Flags >> 3) & 0x01;
HFI.DirInfo = (Flags >> 1) & 0x03;
HFI.Resolved = Flags & 0x01;
HFI.NumIncludes = ReadUnalignedLE16(d);
@@ -1841,6 +1843,22 @@ MacroDefinition *ASTReader::getMacroDefinition(MacroID ID) {
return MacroDefinitionsLoaded[ID - 1];
}
+const FileEntry *ASTReader::getFileEntry(llvm::StringRef filenameStrRef) {
+ std::string Filename = filenameStrRef;
+ MaybeAddSystemRootToFilename(Filename);
+ const FileEntry *File = FileMgr.getFile(Filename);
+ if (File == 0 && !OriginalDir.empty() && !CurrentDir.empty() &&
+ OriginalDir != CurrentDir) {
+ std::string resolved = resolveFileRelativeToOriginalDir(Filename,
+ OriginalDir,
+ CurrentDir);
+ if (!resolved.empty())
+ File = FileMgr.getFile(resolved);
+ }
+
+ return File;
+}
+
/// \brief If we are loading a relocatable PCH file, and the filename is
/// not an absolute path, add the system root to the beginning of the file
/// name.
@@ -2113,15 +2131,6 @@ ASTReader::ReadASTBlock(PerFileData &F) {
TotalVisibleDeclContexts += Record[3];
break;
- case TENTATIVE_DEFINITIONS:
- // Optimization for the first block.
- if (TentativeDefinitions.empty())
- TentativeDefinitions.swap(Record);
- else
- TentativeDefinitions.insert(TentativeDefinitions.end(),
- Record.begin(), Record.end());
- break;
-
case UNUSED_FILESCOPED_DECLS:
// Optimization for the first block.
if (UnusedFileScopedDecls.empty())
@@ -2131,6 +2140,15 @@ ASTReader::ReadASTBlock(PerFileData &F) {
Record.begin(), Record.end());
break;
+ case DELEGATING_CTORS:
+ // Optimization for the first block.
+ if (DelegatingCtorDecls.empty())
+ DelegatingCtorDecls.swap(Record);
+ else
+ DelegatingCtorDecls.insert(DelegatingCtorDecls.end(),
+ Record.begin(), Record.end());
+ break;
+
case WEAK_UNDECLARED_IDENTIFIERS:
// Later blocks overwrite earlier ones.
WeakUndeclaredIdentifiers.swap(Record);
@@ -2176,6 +2194,11 @@ ASTReader::ReadASTBlock(PerFileData &F) {
F.LocalSLocSize = Record[1];
break;
+ case FILE_SOURCE_LOCATION_OFFSETS:
+ F.SLocFileOffsets = (const uint32_t *)BlobStart;
+ F.LocalNumSLocFileEntries = Record[0];
+ break;
+
case SOURCE_LOCATION_PRELOADS:
if (PreloadSLocEntries.empty())
PreloadSLocEntries.swap(Record);
@@ -2236,6 +2259,10 @@ ASTReader::ReadASTBlock(PerFileData &F) {
MaybeAddSystemRootToFilename(OriginalFileName);
break;
+ case ORIGINAL_FILE_ID:
+ OriginalFileID = FileID::get(Record[0]);
+ break;
+
case ORIGINAL_PCH_DIR:
// The primary AST will be the last to get here, so it will be the one
// that's used.
@@ -2330,6 +2357,15 @@ ASTReader::ReadASTBlock(PerFileData &F) {
// Later tables overwrite earlier ones.
OpenCLExtensions.swap(Record);
break;
+
+ case TENTATIVE_DEFINITIONS:
+ // Optimization for the first block.
+ if (TentativeDefinitions.empty())
+ TentativeDefinitions.swap(Record);
+ else
+ TentativeDefinitions.insert(TentativeDefinitions.end(),
+ Record.begin(), Record.end());
+ break;
}
First = false;
}
@@ -2337,6 +2373,75 @@ ASTReader::ReadASTBlock(PerFileData &F) {
return Failure;
}
+ASTReader::ASTReadResult ASTReader::validateFileEntries() {
+ for (unsigned CI = 0, CN = Chain.size(); CI != CN; ++CI) {
+ PerFileData *F = Chain[CI];
+ llvm::BitstreamCursor &SLocEntryCursor = F->SLocEntryCursor;
+
+ for (unsigned i = 0, e = F->LocalNumSLocFileEntries; i != e; ++i) {
+ SLocEntryCursor.JumpToBit(F->SLocFileOffsets[i]);
+ unsigned Code = SLocEntryCursor.ReadCode();
+ if (Code == llvm::bitc::END_BLOCK ||
+ Code == llvm::bitc::ENTER_SUBBLOCK ||
+ Code == llvm::bitc::DEFINE_ABBREV) {
+ Error("incorrectly-formatted source location entry in AST file");
+ return Failure;
+ }
+
+ RecordData Record;
+ const char *BlobStart;
+ unsigned BlobLen;
+ switch (SLocEntryCursor.ReadRecord(Code, Record, &BlobStart, &BlobLen)) {
+ default:
+ Error("incorrectly-formatted source location entry in AST file");
+ return Failure;
+
+ case SM_SLOC_FILE_ENTRY: {
+ llvm::StringRef Filename(BlobStart, BlobLen);
+ const FileEntry *File = getFileEntry(Filename);
+
+ if (File == 0) {
+ std::string ErrorStr = "could not find file '";
+ ErrorStr += Filename;
+ ErrorStr += "' referenced by AST file";
+ Error(ErrorStr.c_str());
+ return IgnorePCH;
+ }
+
+ if (Record.size() < 6) {
+ Error("source location entry is incorrect");
+ return Failure;
+ }
+
+ // The stat info from the FileEntry came from the cached stat
+ // info of the PCH, so we cannot trust it.
+ struct stat StatBuf;
+ if (::stat(File->getName(), &StatBuf) != 0) {
+ StatBuf.st_size = File->getSize();
+ StatBuf.st_mtime = File->getModificationTime();
+ }
+
+ if (((off_t)Record[4] != StatBuf.st_size
+#if !defined(LLVM_ON_WIN32)
+ // In our regression testing, the Windows file system seems to
+ // have inconsistent modification times that sometimes
+ // erroneously trigger this error-handling path.
+ || (time_t)Record[5] != StatBuf.st_mtime
+#endif
+ )) {
+ Error(diag::err_fe_pch_file_modified, Filename);
+ return IgnorePCH;
+ }
+
+ break;
+ }
+ }
+ }
+ }
+
+ return Success;
+}
+
ASTReader::ASTReadResult ASTReader::ReadAST(const std::string &FileName,
ASTFileType Type) {
switch(ReadASTCore(FileName, Type)) {
@@ -2347,6 +2452,14 @@ ASTReader::ASTReadResult ASTReader::ReadAST(const std::string &FileName,
// Here comes stuff that we only do once the entire chain is loaded.
+ if (!DisableValidation) {
+ switch(validateFileEntries()) {
+ case Failure: return Failure;
+ case IgnorePCH: return IgnorePCH;
+ case Success: break;
+ }
+ }
+
// Allocate space for loaded slocentries, identifiers, decls and types.
unsigned TotalNumIdentifiers = 0, TotalNumTypes = 0, TotalNumDecls = 0,
TotalNumPreallocatedPreprocessingEntities = 0, TotalNumMacroDefs = 0,
@@ -2372,7 +2485,7 @@ ASTReader::ASTReadResult ASTReader::ReadAST(const std::string &FileName,
PP->getHeaderSearchInfo().SetExternalLookup(this);
if (TotalNumPreallocatedPreprocessingEntities > 0) {
if (!PP->getPreprocessingRecord())
- PP->createPreprocessingRecord();
+ PP->createPreprocessingRecord(true);
PP->getPreprocessingRecord()->SetExternalSource(*this,
TotalNumPreallocatedPreprocessingEntities);
}
@@ -2441,12 +2554,15 @@ ASTReader::ASTReadResult ASTReader::ReadAST(const std::string &FileName,
// the source manager to the file source file from which the preamble was
// built. This is the only valid way to use a precompiled preamble.
if (Type == Preamble) {
- SourceLocation Loc
- = SourceMgr.getLocation(FileMgr.getFile(getOriginalSourceFile()), 1, 1);
- if (Loc.isValid()) {
- std::pair<FileID, unsigned> Decomposed = SourceMgr.getDecomposedLoc(Loc);
- SourceMgr.SetPreambleFileID(Decomposed.first);
+ if (OriginalFileID.isInvalid()) {
+ SourceLocation Loc
+ = SourceMgr.getLocation(FileMgr.getFile(getOriginalSourceFile()), 1, 1);
+ if (Loc.isValid())
+ OriginalFileID = SourceMgr.getDecomposedLoc(Loc).first;
}
+
+ if (!OriginalFileID.isInvalid())
+ SourceMgr.SetPreambleFileID(OriginalFileID);
}
return Success;
@@ -2571,7 +2687,7 @@ void ASTReader::setPreprocessor(Preprocessor &pp) {
TotalNum += Chain[I]->NumPreallocatedPreprocessingEntities;
if (TotalNum) {
if (!PP->getPreprocessingRecord())
- PP->createPreprocessingRecord();
+ PP->createPreprocessingRecord(true);
PP->getPreprocessingRecord()->SetExternalSource(*this, TotalNum);
}
}
@@ -2819,6 +2935,7 @@ bool ASTReader::ParseLanguageOptions(
PARSE_LANGOPT(ObjCNonFragileABI2);
PARSE_LANGOPT(AppleKext);
PARSE_LANGOPT(ObjCDefaultSynthProperties);
+ PARSE_LANGOPT(ObjCInferRelatedResultType);
PARSE_LANGOPT(NoConstantCFStrings);
PARSE_LANGOPT(PascalStrings);
PARSE_LANGOPT(WritableStrings);
@@ -3182,6 +3299,13 @@ QualType ASTReader::ReadTypeRecord(unsigned Index) {
case TYPE_DECLTYPE:
return Context->getDecltypeType(ReadExpr(*Loc.F));
+ case TYPE_UNARY_TRANSFORM: {
+ QualType BaseType = GetType(Record[0]);
+ QualType UnderlyingType = GetType(Record[1]);
+ UnaryTransformType::UTTKind UKind = (UnaryTransformType::UTTKind)Record[2];
+ return Context->getUnaryTransformType(BaseType, UnderlyingType, UKind);
+ }
+
case TYPE_AUTO:
return Context->getAutoType(GetType(Record[0]));
@@ -3356,14 +3480,14 @@ QualType ASTReader::ReadTypeRecord(unsigned Index) {
TemplateName Name = ReadTemplateName(*Loc.F, Record, Idx);
llvm::SmallVector<TemplateArgument, 8> Args;
ReadTemplateArgumentList(Args, *Loc.F, Record, Idx);
- QualType Canon = GetType(Record[Idx++]);
+ QualType Underlying = GetType(Record[Idx++]);
QualType T;
- if (Canon.isNull())
+ if (Underlying.isNull())
T = Context->getCanonicalTemplateSpecializationType(Name, Args.data(),
Args.size());
else
T = Context->getTemplateSpecializationType(Name, Args.data(),
- Args.size(), Canon);
+ Args.size(), Underlying);
const_cast<Type*>(T.getTypePtr())->setDependent(IsDependent);
return T;
}
@@ -3498,6 +3622,12 @@ void TypeLocReader::VisitTypeOfTypeLoc(TypeOfTypeLoc TL) {
void TypeLocReader::VisitDecltypeTypeLoc(DecltypeTypeLoc TL) {
TL.setNameLoc(ReadSourceLocation(Record, Idx));
}
+void TypeLocReader::VisitUnaryTransformTypeLoc(UnaryTransformTypeLoc TL) {
+ TL.setKWLoc(ReadSourceLocation(Record, Idx));
+ TL.setLParenLoc(ReadSourceLocation(Record, Idx));
+ TL.setRParenLoc(ReadSourceLocation(Record, Idx));
+ TL.setUnderlyingTInfo(Reader.GetTypeSourceInfo(F, Record, Idx));
+}
void TypeLocReader::VisitAutoTypeLoc(AutoTypeLoc TL) {
TL.setNameLoc(ReadSourceLocation(Record, Idx));
}
@@ -4099,6 +4229,13 @@ void ASTReader::InitializeSema(Sema &S) {
SemaObj->UnusedFileScopedDecls.push_back(D);
}
+ // If there were any delegating constructors, add them to Sema's list
+ for (unsigned I = 0, N = DelegatingCtorDecls.size(); I != N; ++I) {
+ CXXConstructorDecl *D
+ = cast<CXXConstructorDecl>(GetDecl(DelegatingCtorDecls[I]));
+ SemaObj->DelegatingCtorDecls.push_back(D);
+ }
+
// If there were any locally-scoped external declarations,
// deserialize them and add them to Sema's table of locally-scoped
// external declarations.
@@ -4710,18 +4847,28 @@ ASTReader::ReadCXXCtorInitializers(PerFileData &F, const RecordData &Record,
bool IsBaseVirtual = false;
FieldDecl *Member = 0;
IndirectFieldDecl *IndirectMember = 0;
+ CXXConstructorDecl *Target = 0;
- bool IsBaseInitializer = Record[Idx++];
- if (IsBaseInitializer) {
+ CtorInitializerType Type = (CtorInitializerType)Record[Idx++];
+ switch (Type) {
+ case CTOR_INITIALIZER_BASE:
BaseClassInfo = GetTypeSourceInfo(F, Record, Idx);
IsBaseVirtual = Record[Idx++];
- } else {
- bool IsIndirectMemberInitializer = Record[Idx++];
- if (IsIndirectMemberInitializer)
- IndirectMember = cast<IndirectFieldDecl>(GetDecl(Record[Idx++]));
- else
- Member = cast<FieldDecl>(GetDecl(Record[Idx++]));
+ break;
+
+ case CTOR_INITIALIZER_DELEGATING:
+ Target = cast<CXXConstructorDecl>(GetDecl(Record[Idx++]));
+ break;
+
+ case CTOR_INITIALIZER_MEMBER:
+ Member = cast<FieldDecl>(GetDecl(Record[Idx++]));
+ break;
+
+ case CTOR_INITIALIZER_INDIRECT_MEMBER:
+ IndirectMember = cast<IndirectFieldDecl>(GetDecl(Record[Idx++]));
+ break;
}
+
SourceLocation MemberOrEllipsisLoc = ReadSourceLocation(F, Record, Idx);
Expr *Init = ReadExpr(F);
SourceLocation LParenLoc = ReadSourceLocation(F, Record, Idx);
@@ -4739,10 +4886,13 @@ ASTReader::ReadCXXCtorInitializers(PerFileData &F, const RecordData &Record,
}
CXXCtorInitializer *BOMInit;
- if (IsBaseInitializer) {
+ if (Type == CTOR_INITIALIZER_BASE) {
BOMInit = new (C) CXXCtorInitializer(C, BaseClassInfo, IsBaseVirtual,
LParenLoc, Init, RParenLoc,
MemberOrEllipsisLoc);
+ } else if (Type == CTOR_INITIALIZER_DELEGATING) {
+ BOMInit = new (C) CXXCtorInitializer(C, MemberOrEllipsisLoc, LParenLoc,
+ Target, Init, RParenLoc);
} else if (IsWritten) {
if (Member)
BOMInit = new (C) CXXCtorInitializer(C, Member, MemberOrEllipsisLoc,
@@ -5050,7 +5200,8 @@ ASTReader::~ASTReader() {
}
ASTReader::PerFileData::PerFileData(ASTFileType Ty)
- : Type(Ty), SizeInBits(0), LocalNumSLocEntries(0), SLocOffsets(0), LocalSLocSize(0),
+ : Type(Ty), SizeInBits(0), LocalNumSLocEntries(0), SLocOffsets(0),
+ SLocFileOffsets(0), LocalSLocSize(0),
LocalNumIdentifiers(0), IdentifierOffsets(0), IdentifierTableData(0),
IdentifierLookupTable(0), LocalNumMacroDefinitions(0),
MacroDefinitionOffsets(0),
diff --git a/lib/Serialization/ASTReaderDecl.cpp b/lib/Serialization/ASTReaderDecl.cpp
index 3a825de..fab2069 100644
--- a/lib/Serialization/ASTReaderDecl.cpp
+++ b/lib/Serialization/ASTReaderDecl.cpp
@@ -125,6 +125,7 @@ namespace clang {
void VisitClassTemplateDecl(ClassTemplateDecl *D);
void VisitFunctionTemplateDecl(FunctionTemplateDecl *D);
void VisitTemplateTemplateParmDecl(TemplateTemplateParmDecl *D);
+ void VisitTypeAliasTemplateDecl(TypeAliasTemplateDecl *D);
void VisitUsingDecl(UsingDecl *D);
void VisitUsingShadowDecl(UsingShadowDecl *D);
void VisitLinkageSpecDecl(LinkageSpecDecl *D);
@@ -173,6 +174,18 @@ uint64_t ASTDeclReader::GetCurrentCursorOffset() {
void ASTDeclReader::Visit(Decl *D) {
DeclVisitor<ASTDeclReader, void>::Visit(D);
+ if (DeclaratorDecl *DD = dyn_cast<DeclaratorDecl>(D)) {
+ if (DD->DeclInfo) {
+ DeclaratorDecl::ExtInfo *Info =
+ DD->DeclInfo.get<DeclaratorDecl::ExtInfo *>();
+ Info->TInfo =
+ GetTypeSourceInfo(Record, Idx);
+ }
+ else {
+ DD->DeclInfo = GetTypeSourceInfo(Record, Idx);
+ }
+ }
+
if (TypeDecl *TD = dyn_cast<TypeDecl>(D)) {
// if we have a fully initialized TypeDecl, we can safely read its type now.
TD->setTypeForDecl(Reader.GetType(TypeIDForTypeDecl).getTypePtrOrNull());
@@ -307,10 +320,8 @@ void ASTDeclReader::VisitDeclaratorDecl(DeclaratorDecl *DD) {
DeclaratorDecl::ExtInfo *Info
= new (*Reader.getContext()) DeclaratorDecl::ExtInfo();
ReadQualifierInfo(*Info, Record, Idx);
- Info->TInfo = GetTypeSourceInfo(Record, Idx);
DD->DeclInfo = Info;
- } else
- DD->DeclInfo = GetTypeSourceInfo(Record, Idx);
+ }
}
void ASTDeclReader::VisitFunctionDecl(FunctionDecl *FD) {
@@ -428,6 +439,8 @@ void ASTDeclReader::VisitFunctionDecl(FunctionDecl *FD) {
FD->HasWrittenPrototype = Record[Idx++];
FD->IsDeleted = Record[Idx++];
FD->IsTrivial = Record[Idx++];
+ FD->IsDefaulted = Record[Idx++];
+ FD->IsExplicitlyDefaulted = Record[Idx++];
FD->HasImplicitReturnZero = Record[Idx++];
FD->EndRangeLoc = ReadSourceLocation(Record, Idx);
@@ -455,6 +468,7 @@ void ASTDeclReader::VisitObjCMethodDecl(ObjCMethodDecl *MD) {
MD->setDefined(Record[Idx++]);
MD->setDeclImplementation((ObjCMethodDecl::ImplementationControl)Record[Idx++]);
MD->setObjCDeclQualifier((Decl::ObjCDeclQualifier)Record[Idx++]);
+ MD->SetRelatedResultType(Record[Idx++]);
MD->setNumSelectorArgs(unsigned(Record[Idx++]));
MD->setResultType(Reader.GetType(Record[Idx++]));
MD->setResultTypeSourceInfo(GetTypeSourceInfo(Record, Idx));
@@ -663,8 +677,11 @@ void ASTDeclReader::VisitObjCPropertyImplDecl(ObjCPropertyImplDecl *D) {
void ASTDeclReader::VisitFieldDecl(FieldDecl *FD) {
VisitDeclaratorDecl(FD);
FD->setMutable(Record[Idx++]);
- if (Record[Idx++])
+ int BitWidthOrInitializer = Record[Idx++];
+ if (BitWidthOrInitializer == 1)
FD->setBitWidth(Reader.ReadExpr(F));
+ else if (BitWidthOrInitializer == 2)
+ FD->setInClassInitializer(Reader.ReadExpr(F));
if (!FD->getDeclName()) {
FieldDecl *Tmpl = cast_or_null<FieldDecl>(Reader.GetDecl(Record[Idx++]));
if (Tmpl)
@@ -857,7 +874,8 @@ void ASTDeclReader::ReadCXXDefinitionData(
Data.HasPrivateFields = Record[Idx++];
Data.HasProtectedFields = Record[Idx++];
Data.HasPublicFields = Record[Idx++];
- Data.HasTrivialConstructor = Record[Idx++];
+ Data.HasMutableFields = Record[Idx++];
+ Data.HasTrivialDefaultConstructor = Record[Idx++];
Data.HasConstExprNonCopyMoveConstructor = Record[Idx++];
Data.HasTrivialCopyConstructor = Record[Idx++];
Data.HasTrivialMoveConstructor = Record[Idx++];
@@ -866,6 +884,7 @@ void ASTDeclReader::ReadCXXDefinitionData(
Data.HasTrivialDestructor = Record[Idx++];
Data.HasNonLiteralTypeFieldsOrBases = Record[Idx++];
Data.ComputedVisibleConversions = Record[Idx++];
+ Data.UserProvidedDefaultConstructor = Record[Idx++];
Data.DeclaredDefaultConstructor = Record[Idx++];
Data.DeclaredCopyConstructor = Record[Idx++];
Data.DeclaredCopyAssignment = Record[Idx++];
@@ -1266,6 +1285,10 @@ void ASTDeclReader::VisitTemplateTemplateParmDecl(TemplateTemplateParmDecl *D) {
D->ParameterPack = Record[Idx++];
}
+void ASTDeclReader::VisitTypeAliasTemplateDecl(TypeAliasTemplateDecl *D) {
+ VisitRedeclarableTemplateDecl(D);
+}
+
void ASTDeclReader::VisitStaticAssertDecl(StaticAssertDecl *D) {
VisitDecl(D);
D->AssertExpr = Reader.ReadExpr(F);
@@ -1380,7 +1403,7 @@ static bool isConsumerInterestedIn(Decl *D) {
return Var->isFileVarDecl() &&
Var->isThisDeclarationADefinition() == VarDecl::Definition;
if (FunctionDecl *Func = dyn_cast<FunctionDecl>(D))
- return Func->isThisDeclarationADefinition();
+ return Func->doesThisDeclarationHaveABody();
return isa<ObjCProtocolDecl>(D) || isa<ObjCImplementationDecl>(D);
}
@@ -1572,6 +1595,9 @@ Decl *ASTReader::ReadDeclRecord(unsigned Index, DeclID ID) {
D = TemplateTemplateParmDecl::Create(*Context, 0, SourceLocation(), 0, 0,
false, 0, 0);
break;
+ case DECL_TYPE_ALIAS_TEMPLATE:
+ D = TypeAliasTemplateDecl::Create(*Context, Decl::EmptyShell());
+ break;
case DECL_STATIC_ASSERT:
D = StaticAssertDecl::Create(*Context, 0, SourceLocation(), 0, 0,
SourceLocation());
@@ -1626,7 +1652,7 @@ Decl *ASTReader::ReadDeclRecord(unsigned Index, DeclID ID) {
break;
case DECL_FIELD:
D = FieldDecl::Create(*Context, 0, SourceLocation(), SourceLocation(), 0,
- QualType(), 0, 0, false);
+ QualType(), 0, 0, false, false);
break;
case DECL_INDIRECTFIELD:
D = IndirectFieldDecl::Create(*Context, 0, SourceLocation(), 0, QualType(),
diff --git a/lib/Serialization/ASTReaderStmt.cpp b/lib/Serialization/ASTReaderStmt.cpp
index 918db7e..f3f67a7 100644
--- a/lib/Serialization/ASTReaderStmt.cpp
+++ b/lib/Serialization/ASTReaderStmt.cpp
@@ -189,7 +189,7 @@ namespace clang {
void VisitOpaqueValueExpr(OpaqueValueExpr *E);
// CUDA Expressions
- void VisitCUDAKernelCallExpr(CUDAKernelCallExpr *E);
+ void VisitCUDAKernelCallExpr(CUDAKernelCallExpr *E);
};
}
@@ -2000,6 +2000,10 @@ Stmt *ASTReader::ReadStmtFromStream(PerFileData &F) {
case EXPR_CUDA_KERNEL_CALL:
S = new (Context) CUDAKernelCallExpr(*Context, Empty);
break;
+
+ case EXPR_ASTYPE:
+ S = new (Context) AsTypeExpr(Empty);
+ break;
}
// We hit a STMT_STOP, so we're done with this expression.
diff --git a/lib/Serialization/ASTWriter.cpp b/lib/Serialization/ASTWriter.cpp
index 6d44fb6..ba9032e 100644
--- a/lib/Serialization/ASTWriter.cpp
+++ b/lib/Serialization/ASTWriter.cpp
@@ -223,6 +223,13 @@ void ASTTypeWriter::VisitDecltypeType(const DecltypeType *T) {
Code = TYPE_DECLTYPE;
}
+void ASTTypeWriter::VisitUnaryTransformType(const UnaryTransformType *T) {
+ Writer.AddTypeRef(T->getBaseType(), Record);
+ Writer.AddTypeRef(T->getUnderlyingType(), Record);
+ Record.push_back(T->getUTTKind());
+ Code = TYPE_UNARY_TRANSFORM;
+}
+
void ASTTypeWriter::VisitAutoType(const AutoType *T) {
Writer.AddTypeRef(T->getDeducedType(), Record);
Code = TYPE_AUTO;
@@ -277,7 +284,8 @@ ASTTypeWriter::VisitTemplateSpecializationType(
for (TemplateSpecializationType::iterator ArgI = T->begin(), ArgE = T->end();
ArgI != ArgE; ++ArgI)
Writer.AddTemplateArgument(*ArgI, Record);
- Writer.AddTypeRef(T->isCanonicalUnqualified() ? QualType()
+ Writer.AddTypeRef(T->isTypeAlias() ? T->getAliasedType() :
+ T->isCanonicalUnqualified() ? QualType()
: T->getCanonicalTypeInternal(),
Record);
Code = TYPE_TEMPLATE_SPECIALIZATION;
@@ -493,6 +501,12 @@ void TypeLocWriter::VisitTypeOfTypeLoc(TypeOfTypeLoc TL) {
void TypeLocWriter::VisitDecltypeTypeLoc(DecltypeTypeLoc TL) {
Writer.AddSourceLocation(TL.getNameLoc(), Record);
}
+void TypeLocWriter::VisitUnaryTransformTypeLoc(UnaryTransformTypeLoc TL) {
+ Writer.AddSourceLocation(TL.getKWLoc(), Record);
+ Writer.AddSourceLocation(TL.getLParenLoc(), Record);
+ Writer.AddSourceLocation(TL.getRParenLoc(), Record);
+ Writer.AddTypeSourceInfo(TL.getUnderlyingTInfo(), Record);
+}
void TypeLocWriter::VisitAutoTypeLoc(AutoTypeLoc TL) {
Writer.AddSourceLocation(TL.getNameLoc(), Record);
}
@@ -726,6 +740,7 @@ void ASTWriter::WriteBlockInfoBlock() {
// AST Top-Level Block.
BLOCK(AST_BLOCK);
RECORD(ORIGINAL_FILE_NAME);
+ RECORD(ORIGINAL_FILE_ID);
RECORD(TYPE_OFFSET);
RECORD(DECL_OFFSET);
RECORD(LANGUAGE_OPTIONS);
@@ -764,6 +779,7 @@ void ASTWriter::WriteBlockInfoBlock() {
RECORD(HEADER_SEARCH_TABLE);
RECORD(FP_PRAGMA_OPTIONS);
RECORD(OPENCL_EXTENSIONS);
+ RECORD(DELEGATING_CTORS);
// SourceManager Block.
BLOCK(SOURCE_MANAGER_BLOCK);
@@ -873,13 +889,14 @@ void ASTWriter::WriteBlockInfoBlock() {
RECORD(DECL_INDIRECTFIELD);
RECORD(DECL_EXPANDED_NON_TYPE_TEMPLATE_PARM_PACK);
+ // Statements and Exprs can occur in the Decls and Types block.
+ AddStmtsExprs(Stream, Record);
+
BLOCK(PREPROCESSOR_DETAIL_BLOCK);
RECORD(PPD_MACRO_INSTANTIATION);
RECORD(PPD_MACRO_DEFINITION);
RECORD(PPD_INCLUSION_DIRECTIVE);
- // Statements and Exprs can occur in the Decls and Types block.
- AddStmtsExprs(Stream, Record);
#undef RECORD
#undef BLOCK
Stream.ExitBlock();
@@ -951,7 +968,7 @@ void ASTWriter::WriteMetadata(ASTContext &Context, const char *isysroot,
const std::string &BlobStr = Chain ? Chain->getFileName() : Target.getTriple().getTriple();
Stream.EmitRecordWithBlob(MetaAbbrevCode, Record, BlobStr);
- // Original file name
+ // Original file name and file ID
SourceManager &SM = Context.getSourceManager();
if (const FileEntry *MainFile = SM.getFileEntryForID(SM.getMainFileID())) {
BitCodeAbbrev *FileAbbrev = new BitCodeAbbrev();
@@ -969,6 +986,10 @@ void ASTWriter::WriteMetadata(ASTContext &Context, const char *isysroot,
RecordData Record;
Record.push_back(ORIGINAL_FILE_NAME);
Stream.EmitRecordWithBlob(FileAbbrevCode, Record, MainFileNameStr);
+
+ Record.clear();
+ Record.push_back(SM.getMainFileID().getOpaqueValue());
+ Stream.EmitRecord(ORIGINAL_FILE_ID, Record);
}
// Original PCH directory
@@ -1029,6 +1050,7 @@ void ASTWriter::WriteLanguageOptions(const LangOptions &LangOpts) {
Record.push_back(LangOpts.AppleKext); // Apple's kernel extensions ABI
Record.push_back(LangOpts.ObjCDefaultSynthProperties); // Objective-C auto-synthesized
// properties enabled.
+ Record.push_back(LangOpts.ObjCInferRelatedResultType);
Record.push_back(LangOpts.NoConstantCFStrings); // non cfstring generation enabled..
Record.push_back(LangOpts.PascalStrings); // Allow Pascal strings
@@ -1280,7 +1302,8 @@ namespace {
using namespace clang::io;
uint64_t Start = Out.tell(); (void)Start;
- unsigned char Flags = (Data.isImport << 3)
+ unsigned char Flags = (Data.isImport << 4)
+ | (Data.isPragmaOnce << 3)
| (Data.DirInfo << 1)
| Data.Resolved;
Emit8(Out, (uint8_t)Flags);
@@ -1428,6 +1451,9 @@ void ASTWriter::WriteSourceManagerBlock(SourceManager &SourceMgr,
// Write out the source location entry table. We skip the first
// entry, which is always the same dummy entry.
std::vector<uint32_t> SLocEntryOffsets;
+ // Write out the offsets of only source location file entries.
+ // We will go through them in ASTReader::validateFileEntries().
+ std::vector<uint32_t> SLocFileEntryOffsets;
RecordData PreloadSLocs;
unsigned BaseSLocID = Chain ? Chain->getTotalNumSLocs() : 0;
SLocEntryOffsets.reserve(SourceMgr.sloc_entry_size() - 1 - BaseSLocID);
@@ -1442,9 +1468,10 @@ void ASTWriter::WriteSourceManagerBlock(SourceManager &SourceMgr,
// Figure out which record code to use.
unsigned Code;
if (SLoc->isFile()) {
- if (SLoc->getFile().getContentCache()->OrigEntry)
+ if (SLoc->getFile().getContentCache()->OrigEntry) {
Code = SM_SLOC_FILE_ENTRY;
- else
+ SLocFileEntryOffsets.push_back(Stream.GetCurrentBitNo());
+ } else
Code = SM_SLOC_BUFFER_ENTRY;
} else
Code = SM_SLOC_INSTANTIATION_ENTRY;
@@ -1544,6 +1571,18 @@ void ASTWriter::WriteSourceManagerBlock(SourceManager &SourceMgr,
Record.push_back(SourceMgr.getNextOffset() - BaseOffset);
Stream.EmitRecordWithBlob(SLocOffsetsAbbrev, Record, data(SLocEntryOffsets));
+ Abbrev = new BitCodeAbbrev();
+ Abbrev->Add(BitCodeAbbrevOp(FILE_SOURCE_LOCATION_OFFSETS));
+ Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 16)); // # of slocs
+ Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // offsets
+ unsigned SLocFileOffsetsAbbrev = Stream.EmitAbbrev(Abbrev);
+
+ Record.clear();
+ Record.push_back(FILE_SOURCE_LOCATION_OFFSETS);
+ Record.push_back(SLocFileEntryOffsets.size());
+ Stream.EmitRecordWithBlob(SLocFileOffsetsAbbrev, Record,
+ data(SLocFileEntryOffsets));
+
// Write the source location entry preloads array, telling the AST
// reader which source locations entries it should load eagerly.
Stream.EmitRecord(SOURCE_LOCATION_PRELOADS, PreloadSLocs);
@@ -2663,8 +2702,15 @@ ASTWriter::ASTWriter(llvm::BitstreamWriter &Stream)
NextSelectorID(FirstSelectorID), FirstMacroID(1), NextMacroID(FirstMacroID),
CollectedStmts(&StmtsToEmit),
NumStatements(0), NumMacros(0), NumLexicalDeclContexts(0),
- NumVisibleDeclContexts(0), FirstCXXBaseSpecifiersID(1),
- NextCXXBaseSpecifiersID(1)
+ NumVisibleDeclContexts(0),
+ FirstCXXBaseSpecifiersID(1), NextCXXBaseSpecifiersID(1),
+ DeclParmVarAbbrev(0), DeclContextLexicalAbbrev(0),
+ DeclContextVisibleLookupAbbrev(0), UpdateVisibleAbbrev(0),
+ DeclRefExprAbbrev(0), CharacterLiteralAbbrev(0),
+ DeclRecordAbbrev(0), IntegerLiteralAbbrev(0),
+ DeclTypedefAbbrev(0),
+ DeclVarAbbrev(0), DeclFieldAbbrev(0),
+ DeclEnumAbbrev(0), DeclObjCIvarAbbrev(0)
{
}
@@ -2722,6 +2768,10 @@ void ASTWriter::WriteASTCore(Sema &SemaRef, MemorizeStatCalls *StatCalls,
for (unsigned i=0, e = SemaRef.UnusedFileScopedDecls.size(); i !=e; ++i)
AddDeclRef(SemaRef.UnusedFileScopedDecls[i], UnusedFileScopedDecls);
+ RecordData DelegatingCtorDecls;
+ for (unsigned i=0, e = SemaRef.DelegatingCtorDecls.size(); i != e; ++i)
+ AddDeclRef(SemaRef.DelegatingCtorDecls[i], DelegatingCtorDecls);
+
RecordData WeakUndeclaredIdentifiers;
if (!SemaRef.WeakUndeclaredIdentifiers.empty()) {
WeakUndeclaredIdentifiers.push_back(
@@ -2826,7 +2876,7 @@ void ASTWriter::WriteASTCore(Sema &SemaRef, MemorizeStatCalls *StatCalls,
// Keep writing types and declarations until all types and
// declarations have been written.
- Stream.EnterSubblock(DECLTYPES_BLOCK_ID, 3);
+ Stream.EnterSubblock(DECLTYPES_BLOCK_ID, NUM_ALLOWED_ABBREVS_SIZE);
WriteDeclsBlockAbbrevs();
while (!DeclTypesToEmit.empty()) {
DeclOrType DOT = DeclTypesToEmit.front();
@@ -2896,6 +2946,10 @@ void ASTWriter::WriteASTCore(Sema &SemaRef, MemorizeStatCalls *StatCalls,
// Write the record containing CUDA-specific declaration references.
if (!CUDASpecialDeclRefs.empty())
Stream.EmitRecord(CUDA_SPECIAL_DECL_REFS, CUDASpecialDeclRefs);
+
+ // Write the delegating constructors.
+ if (!DelegatingCtorDecls.empty())
+ Stream.EmitRecord(DELEGATING_CTORS, DelegatingCtorDecls);
// Some simple statistics
Record.clear();
@@ -2970,6 +3024,14 @@ void ASTWriter::WriteASTChain(Sema &SemaRef, MemorizeStatCalls *StatCalls,
AddDeclRef(SemaRef.UnusedFileScopedDecls[i], UnusedFileScopedDecls);
}
+ // Build a record containing all of the delegating constructor decls in this
+ // file.
+ RecordData DelegatingCtorDecls;
+ for (unsigned i=0, e = SemaRef.DelegatingCtorDecls.size(); i != e; ++i) {
+ if (SemaRef.DelegatingCtorDecls[i]->getPCHLevel() == 0)
+ AddDeclRef(SemaRef.DelegatingCtorDecls[i], DelegatingCtorDecls);
+ }
+
// We write the entire table, overwriting the tables from the chain.
RecordData WeakUndeclaredIdentifiers;
if (!SemaRef.WeakUndeclaredIdentifiers.empty()) {
@@ -3044,7 +3106,7 @@ void ASTWriter::WriteASTChain(Sema &SemaRef, MemorizeStatCalls *StatCalls,
AddDeclRef(SemaRef.getStdBadAlloc(), SemaDeclRefs);
}
- Stream.EnterSubblock(DECLTYPES_BLOCK_ID, 3);
+ Stream.EnterSubblock(DECLTYPES_BLOCK_ID, NUM_ALLOWED_ABBREVS_SIZE);
WriteDeclsBlockAbbrevs();
for (DeclsToRewriteTy::iterator
I = DeclsToRewrite.begin(), E = DeclsToRewrite.end(); I != E; ++I)
@@ -3127,6 +3189,10 @@ void ASTWriter::WriteASTChain(Sema &SemaRef, MemorizeStatCalls *StatCalls,
// Write the record containing declaration references of Sema.
if (!SemaDeclRefs.empty())
Stream.EmitRecord(SEMA_DECL_REFS, SemaDeclRefs);
+
+ // Write the delegating constructors.
+ if (!DelegatingCtorDecls.empty())
+ Stream.EmitRecord(DELEGATING_CTORS, DelegatingCtorDecls);
// Write the updates to DeclContexts.
for (llvm::SmallPtrSet<const DeclContext *, 16>::iterator
@@ -3152,7 +3218,7 @@ void ASTWriter::WriteDeclUpdatesBlocks() {
return;
RecordData OffsetsRecord;
- Stream.EnterSubblock(DECL_UPDATES_BLOCK_ID, 3);
+ Stream.EnterSubblock(DECL_UPDATES_BLOCK_ID, NUM_ALLOWED_ABBREVS_SIZE);
for (DeclUpdateMap::iterator
I = DeclUpdates.begin(), E = DeclUpdates.end(); I != E; ++I) {
const Decl *D = I->first;
@@ -3743,16 +3809,19 @@ void ASTWriter::AddCXXCtorInitializers(
for (unsigned i=0; i != NumCtorInitializers; ++i) {
const CXXCtorInitializer *Init = CtorInitializers[i];
- Record.push_back(Init->isBaseInitializer());
if (Init->isBaseInitializer()) {
+ Record.push_back(CTOR_INITIALIZER_BASE);
AddTypeSourceInfo(Init->getBaseClassInfo(), Record);
Record.push_back(Init->isBaseVirtual());
+ } else if (Init->isDelegatingInitializer()) {
+ Record.push_back(CTOR_INITIALIZER_DELEGATING);
+ AddDeclRef(Init->getTargetConstructor(), Record);
+ } else if (Init->isMemberInitializer()){
+ Record.push_back(CTOR_INITIALIZER_MEMBER);
+ AddDeclRef(Init->getMember(), Record);
} else {
- Record.push_back(Init->isIndirectMemberInitializer());
- if (Init->isIndirectMemberInitializer())
- AddDeclRef(Init->getIndirectMember(), Record);
- else
- AddDeclRef(Init->getMember(), Record);
+ Record.push_back(CTOR_INITIALIZER_INDIRECT_MEMBER);
+ AddDeclRef(Init->getIndirectMember(), Record);
}
AddSourceLocation(Init->getMemberLocation(), Record);
@@ -3787,7 +3856,8 @@ void ASTWriter::AddCXXDefinitionData(const CXXRecordDecl *D, RecordDataImpl &Rec
Record.push_back(Data.HasPrivateFields);
Record.push_back(Data.HasProtectedFields);
Record.push_back(Data.HasPublicFields);
- Record.push_back(Data.HasTrivialConstructor);
+ Record.push_back(Data.HasMutableFields);
+ Record.push_back(Data.HasTrivialDefaultConstructor);
Record.push_back(Data.HasConstExprNonCopyMoveConstructor);
Record.push_back(Data.HasTrivialCopyConstructor);
Record.push_back(Data.HasTrivialMoveConstructor);
@@ -3796,6 +3866,7 @@ void ASTWriter::AddCXXDefinitionData(const CXXRecordDecl *D, RecordDataImpl &Rec
Record.push_back(Data.HasTrivialDestructor);
Record.push_back(Data.HasNonLiteralTypeFieldsOrBases);
Record.push_back(Data.ComputedVisibleConversions);
+ Record.push_back(Data.UserProvidedDefaultConstructor);
Record.push_back(Data.DeclaredDefaultConstructor);
Record.push_back(Data.DeclaredCopyConstructor);
Record.push_back(Data.DeclaredCopyAssignment);
diff --git a/lib/Serialization/ASTWriterDecl.cpp b/lib/Serialization/ASTWriterDecl.cpp
index 1ca00a3..7c24088 100644
--- a/lib/Serialization/ASTWriterDecl.cpp
+++ b/lib/Serialization/ASTWriterDecl.cpp
@@ -86,6 +86,7 @@ namespace clang {
void VisitClassTemplateDecl(ClassTemplateDecl *D);
void VisitFunctionTemplateDecl(FunctionTemplateDecl *D);
void VisitTemplateTemplateParmDecl(TemplateTemplateParmDecl *D);
+ void VisitTypeAliasTemplateDecl(TypeAliasTemplateDecl *D);
void VisitUsingDecl(UsingDecl *D);
void VisitUsingShadowDecl(UsingShadowDecl *D);
void VisitLinkageSpecDecl(LinkageSpecDecl *D);
@@ -123,12 +124,19 @@ namespace clang {
void ASTDeclWriter::Visit(Decl *D) {
DeclVisitor<ASTDeclWriter>::Visit(D);
+ // Source locations require array (variable-length) abbreviations. The
+ // abbreviation infrastructure requires that arrays are encoded last, so
+ // we handle it here in the case of those classes derived from DeclaratorDecl
+ if (DeclaratorDecl *DD = dyn_cast<DeclaratorDecl>(D)){
+ Writer.AddTypeSourceInfo(DD->getTypeSourceInfo(), Record);
+ }
+
// Handle FunctionDecl's body here and write it after all other Stmts/Exprs
// have been written. We want it last because we will not read it back when
// retrieving it from the AST, we'll just lazily set the offset.
if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
- Record.push_back(FD->isThisDeclarationADefinition());
- if (FD->isThisDeclarationADefinition())
+ Record.push_back(FD->doesThisDeclarationHaveABody());
+ if (FD->doesThisDeclarationHaveABody())
Writer.AddStmt(FD->getBody());
}
}
@@ -168,6 +176,18 @@ void ASTDeclWriter::VisitTypeDecl(TypeDecl *D) {
void ASTDeclWriter::VisitTypedefDecl(TypedefDecl *D) {
VisitTypeDecl(D);
Writer.AddTypeSourceInfo(D->getTypeSourceInfo(), Record);
+
+ if (!D->hasAttrs() &&
+ !D->isImplicit() &&
+ !D->isUsed(false) &&
+ D->getPCHLevel() == 0 &&
+ D->RedeclLink.getNext() == D &&
+ !D->isInvalidDecl() &&
+ !D->isReferenced() &&
+ D->getAccess() == AS_none &&
+ D->getDeclName().getNameKind() == DeclarationName::Identifier)
+ AbbrevToUse = Writer.getDeclTypedefAbbrev();
+
Code = serialization::DECL_TYPEDEF;
}
@@ -204,6 +224,21 @@ void ASTDeclWriter::VisitEnumDecl(EnumDecl *D) {
Record.push_back(D->isScopedUsingClassTag());
Record.push_back(D->isFixed());
Writer.AddDeclRef(D->getInstantiatedFromMemberEnum(), Record);
+
+ if (!D->hasAttrs() &&
+ !D->isImplicit() &&
+ !D->isUsed(false) &&
+ D->getPCHLevel() == 0 &&
+ !D->hasExtInfo() &&
+ D->RedeclLink.getNext() == D &&
+ !D->isInvalidDecl() &&
+ !D->isReferenced() &&
+ D->getAccess() == AS_none &&
+ !CXXRecordDecl::classofKind(D->getKind()) &&
+ !D->getIntegerTypeSourceInfo() &&
+ D->getDeclName().getNameKind() == DeclarationName::Identifier)
+ AbbrevToUse = Writer.getDeclEnumAbbrev();
+
Code = serialization::DECL_ENUM;
}
@@ -212,6 +247,20 @@ void ASTDeclWriter::VisitRecordDecl(RecordDecl *D) {
Record.push_back(D->hasFlexibleArrayMember());
Record.push_back(D->isAnonymousStructOrUnion());
Record.push_back(D->hasObjectMember());
+
+ if (!D->hasAttrs() &&
+ !D->isImplicit() &&
+ !D->isUsed(false) &&
+ D->getPCHLevel() == 0 &&
+ !D->hasExtInfo() &&
+ D->RedeclLink.getNext() == D &&
+ !D->isInvalidDecl() &&
+ !D->isReferenced() &&
+ D->getAccess() == AS_none &&
+ !CXXRecordDecl::classofKind(D->getKind()) &&
+ D->getDeclName().getNameKind() == DeclarationName::Identifier)
+ AbbrevToUse = Writer.getDeclRecordAbbrev();
+
Code = serialization::DECL_RECORD;
}
@@ -226,6 +275,7 @@ void ASTDeclWriter::VisitEnumConstantDecl(EnumConstantDecl *D) {
if (D->getInitExpr())
Writer.AddStmt(D->getInitExpr());
Writer.AddAPSInt(D->getInitVal(), Record);
+
Code = serialization::DECL_ENUM_CONSTANT;
}
@@ -235,7 +285,6 @@ void ASTDeclWriter::VisitDeclaratorDecl(DeclaratorDecl *D) {
Record.push_back(D->hasExtInfo());
if (D->hasExtInfo())
Writer.AddQualifierInfo(*D->getExtInfo(), Record);
- Writer.AddTypeSourceInfo(D->getTypeSourceInfo(), Record);
}
void ASTDeclWriter::VisitFunctionDecl(FunctionDecl *D) {
@@ -321,8 +370,10 @@ void ASTDeclWriter::VisitFunctionDecl(FunctionDecl *D) {
Record.push_back(D->isPure());
Record.push_back(D->hasInheritedPrototype());
Record.push_back(D->hasWrittenPrototype());
- Record.push_back(D->isDeleted());
+ Record.push_back(D->isDeletedAsWritten());
Record.push_back(D->isTrivial());
+ Record.push_back(D->isDefaulted());
+ Record.push_back(D->isExplicitlyDefaulted());
Record.push_back(D->hasImplicitReturnZero());
Writer.AddSourceLocation(D->getLocEnd(), Record);
@@ -353,6 +404,7 @@ void ASTDeclWriter::VisitObjCMethodDecl(ObjCMethodDecl *D) {
Record.push_back(D->getImplementationControl());
// FIXME: stable encoding for in/out/inout/bycopy/byref/oneway
Record.push_back(D->getObjCDeclQualifier());
+ Record.push_back(D->hasRelatedResultType());
Record.push_back(D->getNumSelectorArgs());
Writer.AddTypeRef(D->getResultType(), Record);
Writer.AddTypeSourceInfo(D->getResultTypeSourceInfo(), Record);
@@ -413,6 +465,18 @@ void ASTDeclWriter::VisitObjCIvarDecl(ObjCIvarDecl *D) {
// FIXME: stable encoding for @public/@private/@protected/@package
Record.push_back(D->getAccessControl());
Record.push_back(D->getSynthesize());
+
+ if (!D->hasAttrs() &&
+ !D->isImplicit() &&
+ !D->isUsed(false) &&
+ !D->isInvalidDecl() &&
+ !D->isReferenced() &&
+ D->getPCHLevel() == 0 &&
+ !D->getBitWidth() &&
+ !D->hasExtInfo() &&
+ D->getDeclName())
+ AbbrevToUse = Writer.getDeclObjCIvarAbbrev();
+
Code = serialization::DECL_OBJC_IVAR;
}
@@ -535,11 +599,28 @@ void ASTDeclWriter::VisitObjCPropertyImplDecl(ObjCPropertyImplDecl *D) {
void ASTDeclWriter::VisitFieldDecl(FieldDecl *D) {
VisitDeclaratorDecl(D);
Record.push_back(D->isMutable());
- Record.push_back(D->getBitWidth()? 1 : 0);
+ Record.push_back(D->getBitWidth()? 1 : D->hasInClassInitializer() ? 2 : 0);
if (D->getBitWidth())
Writer.AddStmt(D->getBitWidth());
+ else if (D->hasInClassInitializer())
+ Writer.AddStmt(D->getInClassInitializer());
if (!D->getDeclName())
Writer.AddDeclRef(Context.getInstantiatedFromUnnamedFieldDecl(D), Record);
+
+ if (!D->hasAttrs() &&
+ !D->isImplicit() &&
+ !D->isUsed(false) &&
+ !D->isInvalidDecl() &&
+ !D->isReferenced() &&
+ D->getPCHLevel() == 0 &&
+ !D->getBitWidth() &&
+ !D->hasInClassInitializer() &&
+ !D->hasExtInfo() &&
+ !ObjCIvarDecl::classofKind(D->getKind()) &&
+ !ObjCAtDefsFieldDecl::classofKind(D->getKind()) &&
+ D->getDeclName())
+ AbbrevToUse = Writer.getDeclFieldAbbrev();
+
Code = serialization::DECL_FIELD;
}
@@ -577,6 +658,22 @@ void ASTDeclWriter::VisitVarDecl(VarDecl *D) {
Writer.AddSourceLocation(SpecInfo->getPointOfInstantiation(), Record);
}
+ if (!D->hasAttrs() &&
+ !D->isImplicit() &&
+ !D->isUsed(false) &&
+ !D->isInvalidDecl() &&
+ !D->isReferenced() &&
+ D->getAccess() == AS_none &&
+ D->getPCHLevel() == 0 &&
+ D->getDeclName().getNameKind() == DeclarationName::Identifier &&
+ !D->hasExtInfo() &&
+ D->RedeclLink.getNext() == D &&
+ !D->hasCXXDirectInitializer() &&
+ D->getInit() == 0 &&
+ !ParmVarDecl::classofKind(D->getKind()) &&
+ !SpecInfo)
+ AbbrevToUse = Writer.getDeclVarAbbrev();
+
Code = serialization::DECL_VAR;
}
@@ -601,8 +698,8 @@ void ASTDeclWriter::VisitParmVarDecl(ParmVarDecl *D) {
// 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.
- if (!D->getTypeSourceInfo() &&
- !D->hasAttrs() &&
+ if (!D->hasAttrs() &&
+ !D->hasExtInfo() &&
!D->isImplicit() &&
!D->isUsed(false) &&
D->getAccess() == AS_none &&
@@ -615,7 +712,7 @@ void ASTDeclWriter::VisitParmVarDecl(ParmVarDecl *D) {
!D->hasInheritedDefaultArg() &&
D->getInit() == 0 &&
!D->hasUninstantiatedDefaultArg()) // No default expr.
- AbbrevToUse = Writer.getParmVarDeclAbbrev();
+ AbbrevToUse = Writer.getDeclParmVarAbbrev();
// Check things we know are true of *every* PARM_VAR_DECL, which is more than
// just us assuming it.
@@ -1081,6 +1178,11 @@ void ASTDeclWriter::VisitTemplateTemplateParmDecl(TemplateTemplateParmDecl *D) {
Code = serialization::DECL_TEMPLATE_TEMPLATE_PARM;
}
+void ASTDeclWriter::VisitTypeAliasTemplateDecl(TypeAliasTemplateDecl *D) {
+ VisitRedeclarableTemplateDecl(D);
+ Code = serialization::DECL_TYPE_ALIAS_TEMPLATE;
+}
+
void ASTDeclWriter::VisitStaticAssertDecl(StaticAssertDecl *D) {
VisitDecl(D);
Writer.AddStmt(D->getAssertExpr());
@@ -1141,10 +1243,161 @@ void ASTDeclWriter::VisitRedeclarable(Redeclarable<T> *D) {
void ASTWriter::WriteDeclsBlockAbbrevs() {
using namespace llvm;
- // Abbreviation for DECL_PARM_VAR.
- BitCodeAbbrev *Abv = new BitCodeAbbrev();
- Abv->Add(BitCodeAbbrevOp(serialization::DECL_PARM_VAR));
+ BitCodeAbbrev *Abv;
+
+ // Abbreviation for DECL_FIELD
+ Abv = new BitCodeAbbrev();
+ Abv->Add(BitCodeAbbrevOp(serialization::DECL_FIELD));
+ // Decl
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // DeclContext
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // LexicalDeclContext
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Location
+ Abv->Add(BitCodeAbbrevOp(0)); // isInvalidDecl (!?)
+ Abv->Add(BitCodeAbbrevOp(0)); // HasAttrs
+ Abv->Add(BitCodeAbbrevOp(0)); // isImplicit
+ Abv->Add(BitCodeAbbrevOp(0)); // isUsed
+ Abv->Add(BitCodeAbbrevOp(0)); // isReferenced
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 2)); // AccessSpecifier
+ Abv->Add(BitCodeAbbrevOp(0)); // PCH level
+ // NamedDecl
+ Abv->Add(BitCodeAbbrevOp(0)); // NameKind = Identifier
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Name
+ // ValueDecl
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Type
+ // DeclaratorDecl
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // InnerStartLoc
+ Abv->Add(BitCodeAbbrevOp(0)); // hasExtInfo
+ // FieldDecl
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // isMutable
+ Abv->Add(BitCodeAbbrevOp(0)); //getBitWidth
+ // Type Source Info
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6));
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Array));
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // TypeLoc
+ DeclFieldAbbrev = Stream.EmitAbbrev(Abv);
+
+ // Abbreviation for DECL_OBJC_IVAR
+ Abv = new BitCodeAbbrev();
+ Abv->Add(BitCodeAbbrevOp(serialization::DECL_OBJC_IVAR));
+ // Decl
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // DeclContext
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // LexicalDeclContext
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Location
+ Abv->Add(BitCodeAbbrevOp(0)); // isInvalidDecl (!?)
+ Abv->Add(BitCodeAbbrevOp(0)); // HasAttrs
+ Abv->Add(BitCodeAbbrevOp(0)); // isImplicit
+ Abv->Add(BitCodeAbbrevOp(0)); // isUsed
+ Abv->Add(BitCodeAbbrevOp(0)); // isReferenced
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 2)); // AccessSpecifier
+ Abv->Add(BitCodeAbbrevOp(0)); // PCH level
+ // NamedDecl
+ Abv->Add(BitCodeAbbrevOp(0)); // NameKind = Identifier
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Name
+ // ValueDecl
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Type
+ // DeclaratorDecl
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // InnerStartLoc
+ Abv->Add(BitCodeAbbrevOp(0)); // hasExtInfo
+ // FieldDecl
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // isMutable
+ Abv->Add(BitCodeAbbrevOp(0)); //getBitWidth
+ // ObjC Ivar
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // getAccessControl
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // getSynthesize
+ // Type Source Info
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6));
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Array));
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // TypeLoc
+ DeclObjCIvarAbbrev = Stream.EmitAbbrev(Abv);
+
+ // Abbreviation for DECL_ENUM
+ Abv = new BitCodeAbbrev();
+ Abv->Add(BitCodeAbbrevOp(serialization::DECL_ENUM));
+ // Decl
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // DeclContext
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // LexicalDeclContext
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Location
+ Abv->Add(BitCodeAbbrevOp(0)); // isInvalidDecl (!?)
+ Abv->Add(BitCodeAbbrevOp(0)); // HasAttrs
+ Abv->Add(BitCodeAbbrevOp(0)); // isImplicit
+ Abv->Add(BitCodeAbbrevOp(0)); // isUsed
+ Abv->Add(BitCodeAbbrevOp(0)); // isReferenced
+ Abv->Add(BitCodeAbbrevOp(AS_none)); // C++ AccessSpecifier
+ Abv->Add(BitCodeAbbrevOp(0)); // PCH level
+ // NamedDecl
+ Abv->Add(BitCodeAbbrevOp(0)); // NameKind = Identifier
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Name
+ // TypeDecl
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Source Location
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Type Ref
+ // Redeclarable
+ Abv->Add(BitCodeAbbrevOp(0)); // No redeclaration
+ // TagDecl
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // IdentifierNamespace
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // getTagKind
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // isDefinition
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // EmbeddedInDeclarator
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // SourceLocation
+ Abv->Add(BitCodeAbbrevOp(0)); // hasExtInfo
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // TypedefNameAnonDecl
+ // EnumDecl
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // AddTypeRef
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // IntegerType
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // getPromotionType
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // getNumPositiveBits
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // getNumNegativeBits
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // isScoped
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // isScopedUsingClassTag
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // isFixed
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // InstantiatedMembEnum
+ // DC
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // LexicalOffset
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // VisibleOffset
+ DeclEnumAbbrev = Stream.EmitAbbrev(Abv);
+
+ // Abbreviation for DECL_RECORD
+ Abv = new BitCodeAbbrev();
+ Abv->Add(BitCodeAbbrevOp(serialization::DECL_RECORD));
+ // Decl
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // DeclContext
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // LexicalDeclContext
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Location
+ Abv->Add(BitCodeAbbrevOp(0)); // isInvalidDecl (!?)
+ Abv->Add(BitCodeAbbrevOp(0)); // HasAttrs
+ Abv->Add(BitCodeAbbrevOp(0)); // isImplicit
+ Abv->Add(BitCodeAbbrevOp(0)); // isUsed
+ Abv->Add(BitCodeAbbrevOp(0)); // isReferenced
+ Abv->Add(BitCodeAbbrevOp(AS_none)); // C++ AccessSpecifier
+ Abv->Add(BitCodeAbbrevOp(0)); // PCH level
+ // NamedDecl
+ Abv->Add(BitCodeAbbrevOp(0)); // NameKind = Identifier
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Name
+ // TypeDecl
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Source Location
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Type Ref
+ // Redeclarable
+ Abv->Add(BitCodeAbbrevOp(0)); // No redeclaration
+ // TagDecl
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // IdentifierNamespace
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // getTagKind
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // isDefinition
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // EmbeddedInDeclarator
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // SourceLocation
+ Abv->Add(BitCodeAbbrevOp(0)); // hasExtInfo
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // TypedefNameAnonDecl
+ // RecordDecl
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // FlexibleArrayMember
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // AnonymousStructUnion
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // hasObjectMember
+ // DC
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // LexicalOffset
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // VisibleOffset
+ DeclRecordAbbrev = Stream.EmitAbbrev(Abv);
+
+ // Abbreviation for DECL_PARM_VAR
+ Abv = new BitCodeAbbrev();
+ Abv->Add(BitCodeAbbrevOp(serialization::DECL_PARM_VAR));
// Decl
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // DeclContext
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // LexicalDeclContext
@@ -1156,7 +1409,6 @@ void ASTWriter::WriteDeclsBlockAbbrevs() {
Abv->Add(BitCodeAbbrevOp(0)); // isReferenced
Abv->Add(BitCodeAbbrevOp(AS_none)); // C++ AccessSpecifier
Abv->Add(BitCodeAbbrevOp(0)); // PCH level
-
// NamedDecl
Abv->Add(BitCodeAbbrevOp(0)); // NameKind = Identifier
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Name
@@ -1165,7 +1417,6 @@ void ASTWriter::WriteDeclsBlockAbbrevs() {
// DeclaratorDecl
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // InnerStartLoc
Abv->Add(BitCodeAbbrevOp(0)); // hasExtInfo
- Abv->Add(BitCodeAbbrevOp(serialization::PREDEF_TYPE_NULL_ID)); // InfoType
// VarDecl
Abv->Add(BitCodeAbbrevOp(0)); // No redeclaration
Abv->Add(BitCodeAbbrevOp(0)); // StorageClass
@@ -1185,8 +1436,128 @@ void ASTWriter::WriteDeclsBlockAbbrevs() {
Abv->Add(BitCodeAbbrevOp(0)); // KNRPromoted
Abv->Add(BitCodeAbbrevOp(0)); // HasInheritedDefaultArg
Abv->Add(BitCodeAbbrevOp(0)); // HasUninstantiatedDefaultArg
+ // Type Source Info
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6));
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Array));
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // TypeLoc
+ DeclParmVarAbbrev = Stream.EmitAbbrev(Abv);
- ParmVarDeclAbbrev = Stream.EmitAbbrev(Abv);
+ // Abbreviation for DECL_TYPEDEF
+ Abv = new BitCodeAbbrev();
+ Abv->Add(BitCodeAbbrevOp(serialization::DECL_TYPEDEF));
+ // Decl
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // DeclContext
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // LexicalDeclContext
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Location
+ Abv->Add(BitCodeAbbrevOp(0)); // isInvalidDecl (!?)
+ Abv->Add(BitCodeAbbrevOp(0)); // HasAttrs
+ Abv->Add(BitCodeAbbrevOp(0)); // isImplicit
+ Abv->Add(BitCodeAbbrevOp(0)); // isUsed
+ Abv->Add(BitCodeAbbrevOp(0)); // isReferenced
+ Abv->Add(BitCodeAbbrevOp(AS_none)); // C++ AccessSpecifier
+ Abv->Add(BitCodeAbbrevOp(0)); // PCH level
+ // NamedDecl
+ Abv->Add(BitCodeAbbrevOp(0)); // NameKind = Identifier
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Name
+ // TypeDecl
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Source Location
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Type Ref
+ // TypedefDecl
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Array));
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // TypeLoc
+ DeclTypedefAbbrev = Stream.EmitAbbrev(Abv);
+
+ // Abbreviation for DECL_VAR
+ Abv = new BitCodeAbbrev();
+ Abv->Add(BitCodeAbbrevOp(serialization::DECL_VAR));
+ // Decl
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // DeclContext
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // LexicalDeclContext
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Location
+ Abv->Add(BitCodeAbbrevOp(0)); // isInvalidDecl (!?)
+ Abv->Add(BitCodeAbbrevOp(0)); // HasAttrs
+ Abv->Add(BitCodeAbbrevOp(0)); // isImplicit
+ Abv->Add(BitCodeAbbrevOp(0)); // isUsed
+ Abv->Add(BitCodeAbbrevOp(0)); // isReferenced
+ Abv->Add(BitCodeAbbrevOp(AS_none)); // C++ AccessSpecifier
+ Abv->Add(BitCodeAbbrevOp(0)); // PCH level
+ // NamedDecl
+ Abv->Add(BitCodeAbbrevOp(0)); // NameKind = Identifier
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Name
+ // ValueDecl
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Type
+ // DeclaratorDecl
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // InnerStartLoc
+ Abv->Add(BitCodeAbbrevOp(0)); // hasExtInfo
+ // VarDecl
+ Abv->Add(BitCodeAbbrevOp(0)); // No redeclaration
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // StorageClass
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // StorageClassAsWritten
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // isThreadSpecified
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // CXXDirectInitializer
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // isExceptionVariable
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // isNRVOVariable
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // isCXXForRangeDecl
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // HasInit
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // HasMemberSpecInfo
+ // Type Source Info
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6));
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Array));
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // TypeLoc
+ DeclVarAbbrev = Stream.EmitAbbrev(Abv);
+
+ // Abbreviation for EXPR_DECL_REF
+ Abv = new BitCodeAbbrev();
+ Abv->Add(BitCodeAbbrevOp(serialization::EXPR_DECL_REF));
+ //Stmt
+ //Expr
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Type
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); //IsTypeDependent
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); //IsValueDependent
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); //UnexpandedParamPack
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 3)); //GetValueKind
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 3)); //GetObjectKind
+ //DeclRefExpr
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); //HasQualifier
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); //GetDeclFound
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); //ExplicitTemplateArgs
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // DeclRef
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Location
+ DeclRefExprAbbrev = Stream.EmitAbbrev(Abv);
+
+ // Abbreviation for EXPR_INTEGER_LITERAL
+ Abv = new BitCodeAbbrev();
+ Abv->Add(BitCodeAbbrevOp(serialization::EXPR_INTEGER_LITERAL));
+ //Stmt
+ //Expr
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Type
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); //IsTypeDependent
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); //IsValueDependent
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); //UnexpandedParamPack
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 3)); //GetValueKind
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 3)); //GetObjectKind
+ //Integer Literal
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Location
+ Abv->Add(BitCodeAbbrevOp(32)); // Bit Width
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Value
+ IntegerLiteralAbbrev = Stream.EmitAbbrev(Abv);
+
+ // Abbreviation for EXPR_CHARACTER_LITERAL
+ Abv = new BitCodeAbbrev();
+ Abv->Add(BitCodeAbbrevOp(serialization::EXPR_CHARACTER_LITERAL));
+ //Stmt
+ //Expr
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Type
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); //IsTypeDependent
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); //IsValueDependent
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); //UnexpandedParamPack
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 3)); //GetValueKind
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 3)); //GetObjectKind
+ //Character Literal
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // getValue
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Location
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); //IsWide
+ CharacterLiteralAbbrev = Stream.EmitAbbrev(Abv);
Abv = new BitCodeAbbrev();
Abv->Add(BitCodeAbbrevOp(serialization::DECL_CONTEXT_LEXICAL));
diff --git a/lib/Serialization/ASTWriterStmt.cpp b/lib/Serialization/ASTWriterStmt.cpp
index bd5889a..00e2404 100644
--- a/lib/Serialization/ASTWriterStmt.cpp
+++ b/lib/Serialization/ASTWriterStmt.cpp
@@ -30,6 +30,7 @@ namespace clang {
public:
serialization::StmtCode Code;
+ unsigned AbbrevToUse;
ASTStmtWriter(ASTWriter &Writer, ASTWriter::RecordData &Record)
: Writer(Writer), Record(Record) { }
@@ -164,6 +165,8 @@ namespace clang {
// CUDA Expressions
void VisitCUDAKernelCallExpr(CUDAKernelCallExpr *E);
+
+ void VisitAsTypeExpr(AsTypeExpr *E);
};
}
@@ -392,6 +395,14 @@ void ASTStmtWriter::VisitDeclRefExpr(DeclRefExpr *E) {
Record.push_back(NumTemplateArgs);
}
+ DeclarationName::NameKind nk = (E->getDecl()->getDeclName().getNameKind());
+
+ if ((!E->hasExplicitTemplateArgs()) && (!E->hasQualifier()) &&
+ (E->getDecl() == E->getFoundDecl()) &&
+ nk == DeclarationName::Identifier) {
+ AbbrevToUse = Writer.getDeclRefExprAbbrev();
+ }
+
if (E->hasQualifier())
Writer.AddNestedNameSpecifierLoc(E->getQualifierLoc(), Record);
@@ -411,6 +422,11 @@ void ASTStmtWriter::VisitIntegerLiteral(IntegerLiteral *E) {
VisitExpr(E);
Writer.AddSourceLocation(E->getLocation(), Record);
Writer.AddAPInt(E->getValue(), Record);
+
+ if (E->getValue().getBitWidth() == 32) {
+ AbbrevToUse = Writer.getIntegerLiteralAbbrev();
+ }
+
Code = serialization::EXPR_INTEGER_LITERAL;
}
@@ -449,6 +465,9 @@ void ASTStmtWriter::VisitCharacterLiteral(CharacterLiteral *E) {
Record.push_back(E->getValue());
Writer.AddSourceLocation(E->getLocation(), Record);
Record.push_back(E->isWide());
+
+ AbbrevToUse = Writer.getCharacterLiteralAbbrev();
+
Code = serialization::EXPR_CHARACTER_LITERAL;
}
@@ -1416,6 +1435,15 @@ void ASTStmtWriter::VisitCUDAKernelCallExpr(CUDAKernelCallExpr *E) {
}
//===----------------------------------------------------------------------===//
+// OpenCL Expressions and Statements.
+//===----------------------------------------------------------------------===//
+void ASTStmtWriter::VisitAsTypeExpr(AsTypeExpr *E) {
+ VisitExpr(E);
+ Writer.AddStmt(E->getSrcExpr());
+ Code = serialization::EXPR_ASTYPE;
+}
+
+//===----------------------------------------------------------------------===//
// ASTWriter Implementation
//===----------------------------------------------------------------------===//
@@ -1460,6 +1488,7 @@ void ASTWriter::WriteSubStmt(Stmt *S) {
CollectedStmts = &SubStmts;
Writer.Code = serialization::STMT_NULL_PTR;
+ Writer.AbbrevToUse = 0;
Writer.Visit(S);
#ifndef NDEBUG
@@ -1481,7 +1510,7 @@ void ASTWriter::WriteSubStmt(Stmt *S) {
while (!SubStmts.empty())
WriteSubStmt(SubStmts.pop_back_val());
- Stream.EmitRecord(Writer.Code, Record);
+ Stream.EmitRecord(Writer.Code, Record, Writer.AbbrevToUse);
}
/// \brief Flush all of the statements that have been added to the
diff --git a/lib/StaticAnalyzer/Checkers/CStringChecker.cpp b/lib/StaticAnalyzer/Checkers/CStringChecker.cpp
index a6a256a..f2f5c1e 100644
--- a/lib/StaticAnalyzer/Checkers/CStringChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/CStringChecker.cpp
@@ -42,6 +42,7 @@ public:
bool wantsRegionChangeUpdate(const GRState *state) const;
const GRState *checkRegionChanges(const GRState *state,
+ const StoreManager::InvalidatedSymbols *,
const MemRegion * const *Begin,
const MemRegion * const *End) const;
@@ -77,6 +78,7 @@ public:
void evalStrcmp(CheckerContext &C, const CallExpr *CE) const;
void evalStrncmp(CheckerContext &C, const CallExpr *CE) const;
void evalStrcasecmp(CheckerContext &C, const CallExpr *CE) const;
+ void evalStrncasecmp(CheckerContext &C, const CallExpr *CE) const;
void evalStrcmpCommon(CheckerContext &C, const CallExpr *CE,
bool isBounded = false, bool ignoreCase = false) const;
@@ -711,16 +713,13 @@ void CStringChecker::evalCopyCommon(CheckerContext &C,
// If the size is zero, there won't be any actual memory access, so
// just bind the return value to the destination buffer and return.
if (stateZeroSize) {
+ stateZeroSize = stateZeroSize->BindExpr(CE, destVal);
C.addTransition(stateZeroSize);
- if (IsMempcpy)
- state->BindExpr(CE, destVal);
- else
- state->BindExpr(CE, sizeVal);
- return;
}
// If the size can be nonzero, we have to check the other arguments.
if (stateNonZeroSize) {
+ state = stateNonZeroSize;
// Ensure the destination is not null. If it is NULL there will be a
// NULL pointer dereference.
@@ -737,42 +736,55 @@ void CStringChecker::evalCopyCommon(CheckerContext &C,
if (!state)
return;
- // Ensure the buffers do not overlap.
- state = stateNonZeroSize;
+ // Ensure the accesses are valid and that the buffers do not overlap.
state = CheckBufferAccess(C, state, Size, Dest, Source,
/* FirstIsDst = */ true);
if (Restricted)
state = CheckOverlap(C, state, Size, Dest, Source);
- if (state) {
-
- // If this is mempcpy, get the byte after the last byte copied and
- // bind the expr.
- if (IsMempcpy) {
- loc::MemRegionVal *destRegVal = dyn_cast<loc::MemRegionVal>(&destVal);
-
- // Get the length to copy.
- SVal lenVal = state->getSVal(Size);
- NonLoc *lenValNonLoc = dyn_cast<NonLoc>(&lenVal);
-
+ if (!state)
+ return;
+
+ // If this is mempcpy, get the byte after the last byte copied and
+ // bind the expr.
+ if (IsMempcpy) {
+ loc::MemRegionVal *destRegVal = dyn_cast<loc::MemRegionVal>(&destVal);
+ assert(destRegVal && "Destination should be a known MemRegionVal here");
+
+ // Get the length to copy.
+ NonLoc *lenValNonLoc = dyn_cast<NonLoc>(&sizeVal);
+
+ if (lenValNonLoc) {
// Get the byte after the last byte copied.
SVal lastElement = C.getSValBuilder().evalBinOpLN(state, BO_Add,
*destRegVal,
*lenValNonLoc,
Dest->getType());
-
+
// The byte after the last byte copied is the return value.
state = state->BindExpr(CE, lastElement);
+ } else {
+ // If we don't know how much we copied, we can at least
+ // conjure a return value for later.
+ unsigned Count = C.getNodeBuilder().getCurrentBlockCount();
+ SVal result =
+ C.getSValBuilder().getConjuredSymbolVal(NULL, CE, Count);
+ state = state->BindExpr(CE, result);
}
- // Invalidate the destination.
- // FIXME: Even if we can't perfectly model the copy, we should see if we
- // can use LazyCompoundVals to copy the source values into the destination.
- // This would probably remove any existing bindings past the end of the
- // copied region, but that's still an improvement over blank invalidation.
- state = InvalidateBuffer(C, state, Dest, state->getSVal(Dest));
- C.addTransition(state);
+ } else {
+ // All other copies return the destination buffer.
+ // (Well, bcopy() has a void return type, but this won't hurt.)
+ state = state->BindExpr(CE, destVal);
}
+
+ // Invalidate the destination.
+ // FIXME: Even if we can't perfectly model the copy, we should see if we
+ // can use LazyCompoundVals to copy the source values into the destination.
+ // This would probably remove any existing bindings past the end of the
+ // copied region, but that's still an improvement over blank invalidation.
+ state = InvalidateBuffer(C, state, Dest, state->getSVal(Dest));
+ C.addTransition(state);
}
}
@@ -782,7 +794,7 @@ void CStringChecker::evalMemcpy(CheckerContext &C, const CallExpr *CE) const {
// The return value is the address of the destination buffer.
const Expr *Dest = CE->getArg(0);
const GRState *state = C.getState();
- state = state->BindExpr(CE, state->getSVal(Dest));
+
evalCopyCommon(C, CE, state, CE->getArg(2), Dest, CE->getArg(1), true);
}
@@ -800,7 +812,7 @@ void CStringChecker::evalMemmove(CheckerContext &C, const CallExpr *CE) const {
// The return value is the address of the destination buffer.
const Expr *Dest = CE->getArg(0);
const GRState *state = C.getState();
- state = state->BindExpr(CE, state->getSVal(Dest));
+
evalCopyCommon(C, CE, state, CE->getArg(2), Dest, CE->getArg(1));
}
@@ -953,7 +965,7 @@ void CStringChecker::evalStrcpy(CheckerContext &C, const CallExpr *CE) const {
}
void CStringChecker::evalStrncpy(CheckerContext &C, const CallExpr *CE) const {
- // char *strcpy(char *restrict dst, const char *restrict src);
+ // char *strncpy(char *restrict dst, const char *restrict src, size_t n);
evalStrcpyCommon(C, CE,
/* returnEnd = */ false,
/* isBounded = */ true,
@@ -1128,6 +1140,12 @@ void CStringChecker::evalStrcasecmp(CheckerContext &C,
evalStrcmpCommon(C, CE, /* isBounded = */ false, /* ignoreCase = */ true);
}
+void CStringChecker::evalStrncasecmp(CheckerContext &C,
+ const CallExpr *CE) const {
+ //int strncasecmp(const char *restrict s1, const char *restrict s2, size_t n);
+ evalStrcmpCommon(C, CE, /* isBounded = */ true, /* ignoreCase = */ true);
+}
+
void CStringChecker::evalStrcmpCommon(CheckerContext &C, const CallExpr *CE,
bool isBounded, bool ignoreCase) const {
const GRState *state = C.getState();
@@ -1181,31 +1199,17 @@ void CStringChecker::evalStrcmpCommon(CheckerContext &C, const CallExpr *CE,
return;
llvm::APSInt lenInt(CI->getValue());
- // Compare using the bounds provided like strncmp() does.
- if (ignoreCase) {
- // TODO Implement compare_lower(RHS, n) in LLVM StringRef.
- // result = s1StrRef.compare_lower(s2StrRef,
- // (size_t)lenInt.getLimitedValue());
+ // Create substrings of each to compare the prefix.
+ s1StrRef = s1StrRef.substr(0, (size_t)lenInt.getLimitedValue());
+ s2StrRef = s2StrRef.substr(0, (size_t)lenInt.getLimitedValue());
+ }
- // For now, give up.
- return;
- } else {
- // Create substrings of each to compare the prefix.
- llvm::StringRef s1SubStr =
- s1StrRef.substr(0, (size_t)lenInt.getLimitedValue());
- llvm::StringRef s2SubStr =
- s2StrRef.substr(0, (size_t)lenInt.getLimitedValue());
-
- // Compare the substrings.
- result = s1SubStr.compare(s2SubStr);
- }
+ if (ignoreCase) {
+ // Compare string 1 to string 2 the same way strcasecmp() does.
+ result = s1StrRef.compare_lower(s2StrRef);
} else {
// Compare string 1 to string 2 the same way strcmp() does.
- if (ignoreCase) {
- result = s1StrRef.compare_lower(s2StrRef);
- } else {
- result = s1StrRef.compare(s2StrRef);
- }
+ result = s1StrRef.compare(s2StrRef);
}
// Build the SVal of the comparison to bind the return value.
@@ -1243,11 +1247,11 @@ bool CStringChecker::evalCall(const CallExpr *CE, CheckerContext &C) const {
FnCheck evalFunction = llvm::StringSwitch<FnCheck>(Name)
.Cases("memcpy", "__memcpy_chk", &CStringChecker::evalMemcpy)
- .Case("mempcpy", &CStringChecker::evalMempcpy)
+ .Cases("mempcpy", "__mempcpy_chk", &CStringChecker::evalMempcpy)
.Cases("memcmp", "bcmp", &CStringChecker::evalMemcmp)
.Cases("memmove", "__memmove_chk", &CStringChecker::evalMemmove)
.Cases("strcpy", "__strcpy_chk", &CStringChecker::evalStrcpy)
- .Cases("strncpy", "__strncpy_chk", &CStringChecker::evalStrncpy)
+ //.Cases("strncpy", "__strncpy_chk", &CStringChecker::evalStrncpy)
.Cases("stpcpy", "__stpcpy_chk", &CStringChecker::evalStpcpy)
.Cases("strcat", "__strcat_chk", &CStringChecker::evalStrcat)
.Cases("strncat", "__strncat_chk", &CStringChecker::evalStrncat)
@@ -1256,6 +1260,7 @@ bool CStringChecker::evalCall(const CallExpr *CE, CheckerContext &C) const {
.Case("strcmp", &CStringChecker::evalStrcmp)
.Case("strncmp", &CStringChecker::evalStrncmp)
.Case("strcasecmp", &CStringChecker::evalStrcasecmp)
+ .Case("strncasecmp", &CStringChecker::evalStrncasecmp)
.Case("bcopy", &CStringChecker::evalBcopy)
.Default(NULL);
@@ -1311,6 +1316,7 @@ bool CStringChecker::wantsRegionChangeUpdate(const GRState *state) const {
const GRState *
CStringChecker::checkRegionChanges(const GRState *state,
+ const StoreManager::InvalidatedSymbols *,
const MemRegion * const *Begin,
const MemRegion * const *End) const {
CStringLength::EntryMap Entries = state->get<CStringLength>();
diff --git a/lib/StaticAnalyzer/Checkers/NSErrorChecker.cpp b/lib/StaticAnalyzer/Checkers/NSErrorChecker.cpp
index 63a5917..a51d8e0 100644
--- a/lib/StaticAnalyzer/Checkers/NSErrorChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/NSErrorChecker.cpp
@@ -97,7 +97,7 @@ public:
void CFErrorFunctionChecker::checkASTDecl(const FunctionDecl *D,
AnalysisManager &mgr,
BugReporter &BR) const {
- if (!D->isThisDeclarationADefinition())
+ if (!D->doesThisDeclarationHaveABody())
return;
if (!D->getResultType()->isVoidType())
return;
diff --git a/lib/StaticAnalyzer/Core/BasicStore.cpp b/lib/StaticAnalyzer/Core/BasicStore.cpp
index 4faa84c..7c9f45a 100644
--- a/lib/StaticAnalyzer/Core/BasicStore.cpp
+++ b/lib/StaticAnalyzer/Core/BasicStore.cpp
@@ -49,11 +49,11 @@ public:
SVal Retrieve(Store store, Loc loc, QualType T = QualType());
StoreRef invalidateRegion(Store store, const MemRegion *R, const Expr *E,
- unsigned Count, InvalidatedSymbols *IS);
+ unsigned Count, InvalidatedSymbols &IS);
StoreRef invalidateRegions(Store store, const MemRegion * const *Begin,
const MemRegion * const *End, const Expr *E,
- unsigned Count, InvalidatedSymbols *IS,
+ unsigned Count, InvalidatedSymbols &IS,
bool invalidateGlobals,
InvalidatedRegions *Regions);
@@ -538,7 +538,7 @@ StoreRef BasicStoreManager::invalidateRegions(Store store,
const MemRegion * const *I,
const MemRegion * const *End,
const Expr *E, unsigned Count,
- InvalidatedSymbols *IS,
+ InvalidatedSymbols &IS,
bool invalidateGlobals,
InvalidatedRegions *Regions) {
StoreRef newStore(store, *this);
@@ -587,18 +587,16 @@ StoreRef BasicStoreManager::invalidateRegion(Store store,
const MemRegion *R,
const Expr *E,
unsigned Count,
- InvalidatedSymbols *IS) {
+ InvalidatedSymbols &IS) {
R = R->StripCasts();
if (!(isa<VarRegion>(R) || isa<ObjCIvarRegion>(R)))
return StoreRef(store, *this);
- if (IS) {
- BindingsTy B = GetBindings(store);
- if (BindingsTy::data_type *Val = B.lookup(R)) {
- if (SymbolRef Sym = Val->getAsSymbol())
- IS->insert(Sym);
- }
+ BindingsTy B = GetBindings(store);
+ if (BindingsTy::data_type *Val = B.lookup(R)) {
+ if (SymbolRef Sym = Val->getAsSymbol())
+ IS.insert(Sym);
}
QualType T = cast<TypedRegion>(R)->getValueType();
diff --git a/lib/StaticAnalyzer/Core/BasicValueFactory.cpp b/lib/StaticAnalyzer/Core/BasicValueFactory.cpp
index ae8a04c..0ed4ff1 100644
--- a/lib/StaticAnalyzer/Core/BasicValueFactory.cpp
+++ b/lib/StaticAnalyzer/Core/BasicValueFactory.cpp
@@ -101,7 +101,8 @@ const llvm::APSInt& BasicValueFactory::getValue(uint64_t X, unsigned BitWidth,
const llvm::APSInt& BasicValueFactory::getValue(uint64_t X, QualType T) {
unsigned bits = Ctx.getTypeSize(T);
- llvm::APSInt V(bits, T->isUnsignedIntegerType() || Loc::isLocType(T));
+ llvm::APSInt V(bits,
+ T->isUnsignedIntegerOrEnumerationType() || Loc::isLocType(T));
V = X;
return getValue(V);
}
diff --git a/lib/StaticAnalyzer/Core/CFRefCount.cpp b/lib/StaticAnalyzer/Core/CFRefCount.cpp
index d9b1ce8..0512e2f 100644
--- a/lib/StaticAnalyzer/Core/CFRefCount.cpp
+++ b/lib/StaticAnalyzer/Core/CFRefCount.cpp
@@ -930,6 +930,13 @@ RetainSummary* RetainSummaryManager::getSummary(const FunctionDecl* FD) {
S = getPersistentStopSummary();
break;
}
+ // For C++ methods, generate an implicit "stop" summary as well. We
+ // can relax this once we have a clear policy for C++ methods and
+ // ownership attributes.
+ if (isa<CXXMethodDecl>(FD)) {
+ S = getPersistentStopSummary();
+ break;
+ }
// [PR 3337] Use 'getAs<FunctionType>' to strip away any typedefs on the
// function's type.
@@ -1111,15 +1118,11 @@ RetainSummary* RetainSummaryManager::getSummary(const FunctionDecl* FD) {
RetainSummary*
RetainSummaryManager::getCFCreateGetRuleSummary(const FunctionDecl* FD,
StringRef FName) {
-
if (FName.find("Create") != StringRef::npos ||
FName.find("Copy") != StringRef::npos)
return getCFSummaryCreateRule(FD);
- if (FName.find("Get") != StringRef::npos)
- return getCFSummaryGetRule(FD);
-
- return getDefaultSummary();
+ return getCFSummaryGetRule(FD);
}
RetainSummary*
@@ -1233,6 +1236,9 @@ RetainSummaryManager::updateSummaryFromAnnotations(RetainSummary &Summ,
if (FD->getAttr<CFReturnsRetainedAttr>()) {
Summ.setRetEffect(RetEffect::MakeOwned(RetEffect::CF, true));
}
+ else if (FD->getAttr<CFReturnsNotRetainedAttr>()) {
+ Summ.setRetEffect(RetEffect::MakeNotOwned(RetEffect::CF));
+ }
}
}
@@ -1758,6 +1764,15 @@ public:
StmtNodeBuilder& Builder,
const ReturnStmt* S,
ExplodedNode* Pred);
+
+ void evalReturnWithRetEffect(ExplodedNodeSet& Dst,
+ ExprEngine& Engine,
+ StmtNodeBuilder& Builder,
+ const ReturnStmt* S,
+ ExplodedNode* Pred,
+ RetEffect RE, RefVal X,
+ SymbolRef Sym, const GRState *state);
+
// Assumptions.
@@ -2075,7 +2090,7 @@ PathDiagnosticPiece* CFRefReport::VisitNode(const ExplodedNode* N,
}
if (CurrV.isOwned()) {
- os << "+1 retain count (owning reference).";
+ os << "+1 retain count";
if (static_cast<CFRefBug&>(getBugType()).getTF().isGCEnabled()) {
assert(CurrV.getObjKind() == RetEffect::CF);
@@ -2085,7 +2100,7 @@ PathDiagnosticPiece* CFRefReport::VisitNode(const ExplodedNode* N,
}
else {
assert (CurrV.isNotOwned());
- os << "+0 retain count (non-owning reference).";
+ os << "+0 retain count";
}
PathDiagnosticLocation Pos(S, BRC.getSourceManager());
@@ -2217,11 +2232,11 @@ PathDiagnosticPiece* CFRefReport::VisitNode(const ExplodedNode* N,
case RefVal::ReturnedOwned:
os << "Object returned to caller as an owning reference (single retain "
- "count transferred to caller).";
+ "count transferred to caller)";
break;
case RefVal::ReturnedNotOwned:
- os << "Object returned to caller with a +0 (non-owning) retain count.";
+ os << "Object returned to caller with a +0 retain count";
break;
default:
@@ -2354,12 +2369,7 @@ CFRefLeakReport::getEndPath(BugReporterContext& BRC,
llvm::tie(AllocNode, FirstBinding) =
GetAllocationSite(BRC.getStateManager(), EndN, Sym);
- // Get the allocate site.
- assert(AllocNode);
- const Stmt* FirstStmt = cast<PostStmt>(AllocNode->getLocation()).getStmt();
-
SourceManager& SMgr = BRC.getSourceManager();
- unsigned AllocLine =SMgr.getInstantiationLineNumber(FirstStmt->getLocStart());
// Compute an actual location for the leak. Sometimes a leak doesn't
// occur at an actual statement (e.g., transition between blocks; end
@@ -2392,10 +2402,14 @@ CFRefLeakReport::getEndPath(BugReporterContext& BRC,
std::string sbuf;
llvm::raw_string_ostream os(sbuf);
- os << "Object allocated on line " << AllocLine;
+ os << "Object leaked: ";
- if (FirstBinding)
- os << " and stored into '" << FirstBinding->getString() << '\'';
+ if (FirstBinding) {
+ os << "object allocated and stored into '"
+ << FirstBinding->getString() << '\'';
+ }
+ else
+ os << "allocated object";
// Get the retain count.
const RefVal* RV = EndN->getState()->get<RefBindings>(Sym);
@@ -2404,12 +2418,22 @@ CFRefLeakReport::getEndPath(BugReporterContext& BRC,
// FIXME: Per comments in rdar://6320065, "create" only applies to CF
// ojbects. Only "copy", "alloc", "retain" and "new" transfer ownership
// to the caller for NS objects.
- ObjCMethodDecl& MD = cast<ObjCMethodDecl>(EndN->getCodeDecl());
- os << " is returned from a method whose name ('"
- << MD.getSelector().getAsString()
- << "') does not contain 'copy' or otherwise starts with"
- " 'new' or 'alloc'. This violates the naming convention rules given"
- " in the Memory Management Guide for Cocoa (object leaked)";
+ const Decl *D = &EndN->getCodeDecl();
+ if (const ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(D)) {
+ os << " is returned from a method whose name ('"
+ << MD->getSelector().getAsString()
+ << "') does not start with 'copy', 'mutableCopy', 'alloc' or 'new'."
+ " This violates the naming convention rules "
+ " given in the Memory Management Guide for Cocoa";
+ }
+ else {
+ const FunctionDecl *FD = cast<FunctionDecl>(D);
+ os << " is return from a function whose name ('"
+ << FD->getNameAsString()
+ << "') does not contain 'Copy' or 'Create'. This violates the naming"
+ " convention rules given the Memory Management Guide for Core "
+ " Foundation";
+ }
}
else if (RV->getKind() == RefVal::ErrorGCLeakReturned) {
ObjCMethodDecl& MD = cast<ObjCMethodDecl>(EndN->getCodeDecl());
@@ -2421,7 +2445,7 @@ CFRefLeakReport::getEndPath(BugReporterContext& BRC,
}
else
os << " is not referenced later in this execution path and has a retain "
- "count of +" << RV->getCount() << " (object leaked)";
+ "count of +" << RV->getCount();
return new PathDiagnosticEventPiece(L, os.str());
}
@@ -2494,6 +2518,23 @@ static QualType GetReturnType(const Expr* RetE, ASTContext& Ctx) {
return RetTy;
}
+
+// HACK: Symbols that have ref-count state that are referenced directly
+// (not as structure or array elements, or via bindings) by an argument
+// should not have their ref-count state stripped after we have
+// done an invalidation pass.
+//
+// FIXME: This is a global to currently share between CFRefCount and
+// RetainReleaseChecker. Eventually all functionality in CFRefCount should
+// be migrated to RetainReleaseChecker, and we can make this a non-global.
+llvm::DenseSet<SymbolRef> WhitelistedSymbols;
+namespace {
+struct ResetWhiteList {
+ ResetWhiteList() {}
+ ~ResetWhiteList() { WhitelistedSymbols.clear(); }
+};
+}
+
void CFRefCount::evalSummary(ExplodedNodeSet& Dst,
ExprEngine& Eng,
StmtNodeBuilder& Builder,
@@ -2510,12 +2551,9 @@ void CFRefCount::evalSummary(ExplodedNodeSet& Dst,
SymbolRef ErrorSym = 0;
llvm::SmallVector<const MemRegion*, 10> RegionsToInvalidate;
-
- // HACK: Symbols that have ref-count state that are referenced directly
- // (not as structure or array elements, or via bindings) by an argument
- // should not have their ref-count state stripped after we have
- // done an invalidation pass.
- llvm::DenseSet<SymbolRef> WhitelistedSymbols;
+
+ // Use RAII to make sure the whitelist is properly cleared.
+ ResetWhiteList resetWhiteList;
// Invalidate all instance variables of the receiver of a message.
// FIXME: We should be able to do better with inter-procedural analysis.
@@ -2624,20 +2662,14 @@ void CFRefCount::evalSummary(ExplodedNodeSet& Dst,
// NOTE: Even if RegionsToInvalidate is empty, we must still invalidate
// global variables.
- state = state->invalidateRegions(RegionsToInvalidate.data(),
- RegionsToInvalidate.data() +
- RegionsToInvalidate.size(),
- Ex, Count, &IS,
- /* invalidateGlobals = */ true);
-
- for (StoreManager::InvalidatedSymbols::iterator I = IS.begin(),
- E = IS.end(); I!=E; ++I) {
- SymbolRef sym = *I;
- if (WhitelistedSymbols.count(sym))
- continue;
- // Remove any existing reference-count binding.
- state = state->remove<RefBindings>(*I);
- }
+ // NOTE: RetainReleaseChecker handles the actual invalidation of symbols.
+ state =
+ state->invalidateRegions(RegionsToInvalidate.data(),
+ RegionsToInvalidate.data() +
+ RegionsToInvalidate.size(),
+ Ex, Count, &IS,
+ /* invalidateGlobals = */
+ Eng.doesInvalidateGlobals(callOrMsg));
// Evaluate the effect on the message receiver.
if (!ErrorRange.isValid() && Receiver) {
@@ -2946,30 +2978,50 @@ void CFRefCount::evalReturn(ExplodedNodeSet& Dst,
assert(T);
X = *T;
+ // Consult the summary of the enclosing method.
+ Decl const *CD = &Pred->getCodeDecl();
+
+ if (const ObjCMethodDecl* MD = dyn_cast<ObjCMethodDecl>(CD)) {
+ const RetainSummary &Summ = *Summaries.getMethodSummary(MD);
+ return evalReturnWithRetEffect(Dst, Eng, Builder, S,
+ Pred, Summ.getRetEffect(), X,
+ Sym, state);
+ }
+
+ if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(CD)) {
+ if (!isa<CXXMethodDecl>(FD))
+ if (const RetainSummary *Summ = Summaries.getSummary(FD))
+ return evalReturnWithRetEffect(Dst, Eng, Builder, S,
+ Pred, Summ->getRetEffect(), X,
+ Sym, state);
+ }
+}
+
+void CFRefCount::evalReturnWithRetEffect(ExplodedNodeSet &Dst,
+ ExprEngine &Eng,
+ StmtNodeBuilder &Builder,
+ const ReturnStmt *S,
+ ExplodedNode *Pred,
+ RetEffect RE, RefVal X,
+ SymbolRef Sym, const GRState *state) {
// Any leaks or other errors?
if (X.isReturnedOwned() && X.getCount() == 0) {
- Decl const *CD = &Pred->getCodeDecl();
- if (const ObjCMethodDecl* MD = dyn_cast<ObjCMethodDecl>(CD)) {
- const RetainSummary &Summ = *Summaries.getMethodSummary(MD);
- RetEffect RE = Summ.getRetEffect();
+ if (RE.getKind() != RetEffect::NoRet) {
bool hasError = false;
-
- if (RE.getKind() != RetEffect::NoRet) {
- if (isGCEnabled() && RE.getObjKind() == RetEffect::ObjC) {
- // Things are more complicated with garbage collection. If the
- // returned object is suppose to be an Objective-C object, we have
- // a leak (as the caller expects a GC'ed object) because no
- // method should return ownership unless it returns a CF object.
- hasError = true;
- X = X ^ RefVal::ErrorGCLeakReturned;
- }
- else if (!RE.isOwned()) {
- // Either we are using GC and the returned object is a CF type
- // or we aren't using GC. In either case, we expect that the
- // enclosing method is expected to return ownership.
- hasError = true;
- X = X ^ RefVal::ErrorLeakReturned;
- }
+ if (isGCEnabled() && RE.getObjKind() == RetEffect::ObjC) {
+ // Things are more complicated with garbage collection. If the
+ // returned object is suppose to be an Objective-C object, we have
+ // a leak (as the caller expects a GC'ed object) because no
+ // method should return ownership unless it returns a CF object.
+ hasError = true;
+ X = X ^ RefVal::ErrorGCLeakReturned;
+ }
+ else if (!RE.isOwned()) {
+ // Either we are using GC and the returned object is a CF type
+ // or we aren't using GC. In either case, we expect that the
+ // enclosing method is expected to return ownership.
+ hasError = true;
+ X = X ^ RefVal::ErrorLeakReturned;
}
if (hasError) {
@@ -2987,26 +3039,24 @@ void CFRefCount::evalReturn(ExplodedNodeSet& Dst,
}
}
}
+ return;
}
- else if (X.isReturnedNotOwned()) {
- Decl const *CD = &Pred->getCodeDecl();
- if (const ObjCMethodDecl* MD = dyn_cast<ObjCMethodDecl>(CD)) {
- const RetainSummary &Summ = *Summaries.getMethodSummary(MD);
- if (Summ.getRetEffect().isOwned()) {
- // Trying to return a not owned object to a caller expecting an
- // owned object.
-
- static int ReturnNotOwnedForOwnedTag = 0;
- state = state->set<RefBindings>(Sym, X ^ RefVal::ErrorReturnedNotOwned);
- if (ExplodedNode *N =
- Builder.generateNode(PostStmt(S, Pred->getLocationContext(),
- &ReturnNotOwnedForOwnedTag),
- state, Pred)) {
- CFRefReport *report =
- new CFRefReport(*static_cast<CFRefBug*>(returnNotOwnedForOwned),
- *this, N, Sym);
- BR->EmitReport(report);
- }
+
+ if (X.isReturnedNotOwned()) {
+ if (RE.isOwned()) {
+ // Trying to return a not owned object to a caller expecting an
+ // owned object.
+
+ static int ReturnNotOwnedForOwnedTag = 0;
+ state = state->set<RefBindings>(Sym, X ^ RefVal::ErrorReturnedNotOwned);
+ if (ExplodedNode *N =
+ Builder.generateNode(PostStmt(S, Pred->getLocationContext(),
+ &ReturnNotOwnedForOwnedTag),
+ state, Pred)) {
+ CFRefReport *report =
+ new CFRefReport(*static_cast<CFRefBug*>(returnNotOwnedForOwned),
+ *this, N, Sym);
+ BR->EmitReport(report);
}
}
}
@@ -3418,12 +3468,43 @@ void CFRefCount::ProcessNonLeakError(ExplodedNodeSet& Dst,
namespace {
class RetainReleaseChecker
- : public Checker< check::PostStmt<BlockExpr> > {
+ : public Checker< check::PostStmt<BlockExpr>, check::RegionChanges > {
public:
+ bool wantsRegionUpdate;
+
+ RetainReleaseChecker() : wantsRegionUpdate(true) {}
+
+
void checkPostStmt(const BlockExpr *BE, CheckerContext &C) const;
+ const GRState *checkRegionChanges(const GRState *state,
+ const StoreManager::InvalidatedSymbols *invalidated,
+ const MemRegion * const *begin,
+ const MemRegion * const *end) const;
+
+ bool wantsRegionChangeUpdate(const GRState *state) const {
+ return wantsRegionUpdate;
+ }
};
} // end anonymous namespace
+const GRState *
+RetainReleaseChecker::checkRegionChanges(const GRState *state,
+ const StoreManager::InvalidatedSymbols *invalidated,
+ const MemRegion * const *begin,
+ const MemRegion * const *end) const {
+ if (!invalidated)
+ return state;
+
+ for (StoreManager::InvalidatedSymbols::const_iterator I=invalidated->begin(),
+ E = invalidated->end(); I!=E; ++I) {
+ SymbolRef sym = *I;
+ if (WhitelistedSymbols.count(sym))
+ continue;
+ // Remove any existing reference-count binding.
+ state = state->remove<RefBindings>(sym);
+ }
+ return state;
+}
void RetainReleaseChecker::checkPostStmt(const BlockExpr *BE,
CheckerContext &C) const {
diff --git a/lib/StaticAnalyzer/Core/CXXExprEngine.cpp b/lib/StaticAnalyzer/Core/CXXExprEngine.cpp
index 54cbca0..ef7bc20 100644
--- a/lib/StaticAnalyzer/Core/CXXExprEngine.cpp
+++ b/lib/StaticAnalyzer/Core/CXXExprEngine.cpp
@@ -132,7 +132,7 @@ void ExprEngine::VisitCXXConstructExpr(const CXXConstructExpr *E,
assert(CD);
#if 0
- if (!(CD->isThisDeclarationADefinition() && AMgr.shouldInlineCall()))
+ if (!(CD->doesThisDeclarationHaveABody() && AMgr.shouldInlineCall()))
// FIXME: invalidate the object.
return;
#endif
@@ -246,7 +246,7 @@ void ExprEngine::VisitCXXDestructor(const CXXDestructorDecl *DD,
const Stmt *S,
ExplodedNode *Pred,
ExplodedNodeSet &Dst) {
- if (!(DD->isThisDeclarationADefinition() && AMgr.shouldInlineCall()))
+ if (!(DD->doesThisDeclarationHaveABody() && AMgr.shouldInlineCall()))
return;
// Create the context for 'this' region.
const StackFrameContext *SFC = AMgr.getStackFrame(DD,
diff --git a/lib/StaticAnalyzer/Core/CheckerManager.cpp b/lib/StaticAnalyzer/Core/CheckerManager.cpp
index 4a25490..ba7c384 100644
--- a/lib/StaticAnalyzer/Core/CheckerManager.cpp
+++ b/lib/StaticAnalyzer/Core/CheckerManager.cpp
@@ -345,6 +345,7 @@ bool CheckerManager::wantsRegionChangeUpdate(const GRState *state) {
/// \brief Run checkers for region changes.
const GRState *
CheckerManager::runCheckersForRegionChanges(const GRState *state,
+ const StoreManager::InvalidatedSymbols *invalidated,
const MemRegion * const *Begin,
const MemRegion * const *End) {
for (unsigned i = 0, e = RegionChangesCheckers.size(); i != e; ++i) {
@@ -352,7 +353,7 @@ CheckerManager::runCheckersForRegionChanges(const GRState *state,
// bail out.
if (!state)
return NULL;
- state = RegionChangesCheckers[i].CheckFn(state, Begin, End);
+ state = RegionChangesCheckers[i].CheckFn(state, invalidated, Begin, End);
}
return state;
}
@@ -415,6 +416,15 @@ void CheckerManager::runCheckersForEvalCall(ExplodedNodeSet &Dst,
}
}
+/// \brief Run checkers for the entire Translation Unit.
+void CheckerManager::runCheckersOnEndOfTranslationUnit(
+ const TranslationUnitDecl *TU,
+ AnalysisManager &mgr,
+ BugReporter &BR) {
+ for (unsigned i = 0, e = EndOfTranslationUnitCheckers.size(); i != e; ++i)
+ EndOfTranslationUnitCheckers[i](TU, mgr, BR);
+}
+
//===----------------------------------------------------------------------===//
// Internal registration functions for AST traversing.
//===----------------------------------------------------------------------===//
@@ -494,6 +504,11 @@ void CheckerManager::_registerForEvalCall(EvalCallFunc checkfn) {
EvalCallCheckers.push_back(checkfn);
}
+void CheckerManager::_registerForEndOfTranslationUnit(
+ CheckEndOfTranslationUnit checkfn) {
+ EndOfTranslationUnitCheckers.push_back(checkfn);
+}
+
//===----------------------------------------------------------------------===//
// Implementation details.
//===----------------------------------------------------------------------===//
diff --git a/lib/StaticAnalyzer/Core/Environment.cpp b/lib/StaticAnalyzer/Core/Environment.cpp
index a00f9dc1..48f126b 100644
--- a/lib/StaticAnalyzer/Core/Environment.cpp
+++ b/lib/StaticAnalyzer/Core/Environment.cpp
@@ -39,6 +39,9 @@ SVal Environment::getSVal(const Stmt *E, SValBuilder& svalBuilder,
}
for (;;) {
+ if (const Expr *Ex = dyn_cast<Expr>(E))
+ E = Ex->IgnoreParens();
+
switch (E->getStmtClass()) {
case Stmt::AddrLabelExprClass:
return svalBuilder.makeLoc(cast<AddrLabelExpr>(E));
@@ -48,13 +51,10 @@ SVal Environment::getSVal(const Stmt *E, SValBuilder& svalBuilder,
continue;
}
case Stmt::ParenExprClass:
- // ParenExprs are no-ops.
- E = cast<ParenExpr>(E)->getSubExpr();
- continue;
case Stmt::GenericSelectionExprClass:
- // GenericSelectionExprs are no-ops.
- E = cast<GenericSelectionExpr>(E)->getResultExpr();
- continue;
+ llvm_unreachable("ParenExprs and GenericSelectionExprs should "
+ "have been handled by IgnoreParens()");
+ return UnknownVal();
case Stmt::CharacterLiteralClass: {
const CharacterLiteral* C = cast<CharacterLiteral>(E);
return svalBuilder.makeIntVal(C->getValue(), C->getType());
@@ -77,21 +77,6 @@ SVal Environment::getSVal(const Stmt *E, SValBuilder& svalBuilder,
// For special C0xx nullptr case, make a null pointer SVal.
case Stmt::CXXNullPtrLiteralExprClass:
return svalBuilder.makeNull();
- case Stmt::ImplicitCastExprClass:
- case Stmt::CXXFunctionalCastExprClass:
- case Stmt::CStyleCastExprClass: {
- // We blast through no-op casts to get the descendant
- // subexpression that has a value.
- const CastExpr* C = cast<CastExpr>(E);
- QualType CT = C->getType();
- if (CT->isVoidType())
- return UnknownVal();
- if (C->getCastKind() == CK_NoOp) {
- E = C->getSubExpr();
- continue;
- }
- break;
- }
case Stmt::ExprWithCleanupsClass:
E = cast<ExprWithCleanups>(E)->getSubExpr();
continue;
diff --git a/lib/StaticAnalyzer/Core/ExprEngine.cpp b/lib/StaticAnalyzer/Core/ExprEngine.cpp
index 657420d..aed39eb 100644
--- a/lib/StaticAnalyzer/Core/ExprEngine.cpp
+++ b/lib/StaticAnalyzer/Core/ExprEngine.cpp
@@ -156,6 +156,27 @@ const GRState* ExprEngine::getInitialState(const LocationContext *InitLoc) {
return state;
}
+bool
+ExprEngine::doesInvalidateGlobals(const CallOrObjCMessage &callOrMessage) const
+{
+ if (callOrMessage.isFunctionCall() && !callOrMessage.isCXXCall()) {
+ SVal calleeV = callOrMessage.getFunctionCallee();
+ if (const FunctionTextRegion *codeR =
+ llvm::dyn_cast_or_null<FunctionTextRegion>(calleeV.getAsRegion())) {
+
+ const FunctionDecl *fd = codeR->getDecl();
+ if (const IdentifierInfo *ii = fd->getIdentifier()) {
+ llvm::StringRef fname = ii->getName();
+ if (fname == "strlen")
+ return false;
+ }
+ }
+ }
+
+ // The conservative answer: invalidates globals.
+ return true;
+}
+
//===----------------------------------------------------------------------===//
// Top-level transfer function logic (Dispatcher).
//===----------------------------------------------------------------------===//
@@ -179,9 +200,11 @@ bool ExprEngine::wantsRegionChangeUpdate(const GRState* state) {
const GRState *
ExprEngine::processRegionChanges(const GRState *state,
- const MemRegion * const *Begin,
- const MemRegion * const *End) {
- return getCheckerManager().runCheckersForRegionChanges(state, Begin, End);
+ const StoreManager::InvalidatedSymbols *invalidated,
+ const MemRegion * const *Begin,
+ const MemRegion * const *End) {
+ return getCheckerManager().runCheckersForRegionChanges(state, invalidated,
+ Begin, End);
}
void ExprEngine::processEndWorklist(bool hasWorkRemaining) {
@@ -516,6 +539,7 @@ void ExprEngine::Visit(const Stmt* S, ExplodedNode* Pred,
case Stmt::VAArgExprClass:
case Stmt::CUDAKernelCallExprClass:
case Stmt::OpaqueValueExprClass:
+ case Stmt::AsTypeExprClass:
// Fall through.
// Cases we intentionally don't evaluate, since they don't need
@@ -2462,7 +2486,7 @@ void ExprEngine::VisitOffsetOfExpr(const OffsetOfExpr* OOE,
const APSInt &IV = Res.Val.getInt();
assert(IV.getBitWidth() == getContext().getTypeSize(OOE->getType()));
assert(OOE->getType()->isIntegerType());
- assert(IV.isSigned() == OOE->getType()->isSignedIntegerType());
+ assert(IV.isSigned() == OOE->getType()->isSignedIntegerOrEnumerationType());
SVal X = svalBuilder.makeIntVal(IV);
MakeNode(Dst, OOE, Pred, GetState(Pred)->BindExpr(OOE, X));
return;
@@ -2701,7 +2725,7 @@ void ExprEngine::VisitUnaryOperator(const UnaryOperator* U,
if (U->isLValue())
state = state->BindExpr(U, loc);
else
- state = state->BindExpr(U, V2);
+ state = state->BindExpr(U, U->isPostfix() ? V2 : Result);
// Perform the store.
evalStore(Dst, NULL, U, *I2, state, loc, Result);
diff --git a/lib/StaticAnalyzer/Core/FlatStore.cpp b/lib/StaticAnalyzer/Core/FlatStore.cpp
index 7bdca6b..ca867ae 100644
--- a/lib/StaticAnalyzer/Core/FlatStore.cpp
+++ b/lib/StaticAnalyzer/Core/FlatStore.cpp
@@ -59,7 +59,7 @@ public:
StoreRef invalidateRegions(Store store, const MemRegion * const *I,
const MemRegion * const *E, const Expr *Ex,
- unsigned Count, InvalidatedSymbols *IS,
+ unsigned Count, InvalidatedSymbols &IS,
bool invalidateGlobals,
InvalidatedRegions *Regions);
@@ -175,7 +175,7 @@ StoreRef FlatStoreManager::invalidateRegions(Store store,
const MemRegion * const *I,
const MemRegion * const *E,
const Expr *Ex, unsigned Count,
- InvalidatedSymbols *IS,
+ InvalidatedSymbols &IS,
bool invalidateGlobals,
InvalidatedRegions *Regions) {
assert(false && "Not implemented");
diff --git a/lib/StaticAnalyzer/Core/GRState.cpp b/lib/StaticAnalyzer/Core/GRState.cpp
index 7b21677..0f6ff1e 100644
--- a/lib/StaticAnalyzer/Core/GRState.cpp
+++ b/lib/StaticAnalyzer/Core/GRState.cpp
@@ -141,6 +141,20 @@ const GRState *GRState::invalidateRegions(const MemRegion * const *Begin,
const Expr *E, unsigned Count,
StoreManager::InvalidatedSymbols *IS,
bool invalidateGlobals) const {
+ if (!IS) {
+ StoreManager::InvalidatedSymbols invalidated;
+ return invalidateRegionsImpl(Begin, End, E, Count,
+ invalidated, invalidateGlobals);
+ }
+ return invalidateRegionsImpl(Begin, End, E, Count, *IS, invalidateGlobals);
+}
+
+const GRState *
+GRState::invalidateRegionsImpl(const MemRegion * const *Begin,
+ const MemRegion * const *End,
+ const Expr *E, unsigned Count,
+ StoreManager::InvalidatedSymbols &IS,
+ bool invalidateGlobals) const {
GRStateManager &Mgr = getStateManager();
SubEngine* Eng = Mgr.getOwningEngine();
@@ -150,7 +164,7 @@ const GRState *GRState::invalidateRegions(const MemRegion * const *Begin,
= Mgr.StoreMgr->invalidateRegions(getStore(), Begin, End, E, Count, IS,
invalidateGlobals, &Regions);
const GRState *newState = makeWithStore(newStore);
- return Eng->processRegionChanges(newState,
+ return Eng->processRegionChanges(newState, &IS,
&Regions.front(),
&Regions.back()+1);
}
diff --git a/lib/StaticAnalyzer/Core/ObjCMessage.cpp b/lib/StaticAnalyzer/Core/ObjCMessage.cpp
index c005819..c000600 100644
--- a/lib/StaticAnalyzer/Core/ObjCMessage.cpp
+++ b/lib/StaticAnalyzer/Core/ObjCMessage.cpp
@@ -141,6 +141,13 @@ SVal CallOrObjCMessage::getArgSValAsScalarOrLoc(unsigned i) const {
return UnknownVal();
}
+SVal CallOrObjCMessage::getFunctionCallee() const {
+ assert(isFunctionCall());
+ assert(!isCXXCall());
+ const Expr *callee = CallE->getCallee()->IgnoreParenCasts();
+ return State->getSVal(callee);
+}
+
SVal CallOrObjCMessage::getCXXCallee() const {
assert(isCXXCall());
const Expr *callee =
diff --git a/lib/StaticAnalyzer/Core/RegionStore.cpp b/lib/StaticAnalyzer/Core/RegionStore.cpp
index 4522f97..d0d8f60 100644
--- a/lib/StaticAnalyzer/Core/RegionStore.cpp
+++ b/lib/StaticAnalyzer/Core/RegionStore.cpp
@@ -240,7 +240,7 @@ public:
const MemRegion * const *Begin,
const MemRegion * const *End,
const Expr *E, unsigned Count,
- InvalidatedSymbols *IS,
+ InvalidatedSymbols &IS,
bool invalidateGlobals,
InvalidatedRegions *Regions);
@@ -586,14 +586,14 @@ class invalidateRegionsWorker : public ClusterAnalysis<invalidateRegionsWorker>
{
const Expr *Ex;
unsigned Count;
- StoreManager::InvalidatedSymbols *IS;
+ StoreManager::InvalidatedSymbols &IS;
StoreManager::InvalidatedRegions *Regions;
public:
invalidateRegionsWorker(RegionStoreManager &rm,
GRStateManager &stateMgr,
RegionBindings b,
const Expr *ex, unsigned count,
- StoreManager::InvalidatedSymbols *is,
+ StoreManager::InvalidatedSymbols &is,
StoreManager::InvalidatedRegions *r,
bool includeGlobals)
: ClusterAnalysis<invalidateRegionsWorker>(rm, stateMgr, b, includeGlobals),
@@ -609,9 +609,8 @@ private:
void invalidateRegionsWorker::VisitBinding(SVal V) {
// A symbol? Mark it touched by the invalidation.
- if (IS)
- if (SymbolRef Sym = V.getAsSymbol())
- IS->insert(Sym);
+ if (SymbolRef Sym = V.getAsSymbol())
+ IS.insert(Sym);
if (const MemRegion *R = V.getAsRegion()) {
AddToWorkList(R);
@@ -648,11 +647,9 @@ void invalidateRegionsWorker::VisitCluster(const MemRegion *baseR,
}
void invalidateRegionsWorker::VisitBaseRegion(const MemRegion *baseR) {
- if (IS) {
- // Symbolic region? Mark that symbol touched by the invalidation.
- if (const SymbolicRegion *SR = dyn_cast<SymbolicRegion>(baseR))
- IS->insert(SR->getSymbol());
- }
+ // Symbolic region? Mark that symbol touched by the invalidation.
+ if (const SymbolicRegion *SR = dyn_cast<SymbolicRegion>(baseR))
+ IS.insert(SR->getSymbol());
// BlockDataRegion? If so, invalidate captured variables that are passed
// by reference.
@@ -724,7 +721,7 @@ StoreRef RegionStoreManager::invalidateRegions(Store store,
const MemRegion * const *I,
const MemRegion * const *E,
const Expr *Ex, unsigned Count,
- InvalidatedSymbols *IS,
+ InvalidatedSymbols &IS,
bool invalidateGlobals,
InvalidatedRegions *Regions) {
invalidateRegionsWorker W(*this, StateMgr,
@@ -1066,6 +1063,11 @@ SVal RegionStoreManager::RetrieveElement(Store store,
// return *y;
// FIXME: This is a hack, and doesn't do anything really intelligent yet.
const RegionRawOffset &O = R->getAsArrayOffset();
+
+ // If we cannot reason about the offset, return an unknown value.
+ if (!O.getRegion())
+ return UnknownVal();
+
if (const TypedRegion *baseR = dyn_cast_or_null<TypedRegion>(O.getRegion())) {
QualType baseT = baseR->getValueType();
if (baseT->isScalarType()) {
diff --git a/lib/StaticAnalyzer/Core/SimpleConstraintManager.cpp b/lib/StaticAnalyzer/Core/SimpleConstraintManager.cpp
index 1ee694e..20762e0 100644
--- a/lib/StaticAnalyzer/Core/SimpleConstraintManager.cpp
+++ b/lib/StaticAnalyzer/Core/SimpleConstraintManager.cpp
@@ -262,7 +262,8 @@ const GRState *SimpleConstraintManager::assumeSymRel(const GRState *state,
QualType T = Sym->getType(Ctx);
assert(T->isIntegerType() || Loc::isLocType(T));
unsigned bitwidth = Ctx.getTypeSize(T);
- bool isSymUnsigned = T->isUnsignedIntegerType() || Loc::isLocType(T);
+ bool isSymUnsigned
+ = T->isUnsignedIntegerOrEnumerationType() || Loc::isLocType(T);
// Convert the adjustment.
Adjustment.setIsUnsigned(isSymUnsigned);
diff --git a/lib/StaticAnalyzer/Core/SimpleSValBuilder.cpp b/lib/StaticAnalyzer/Core/SimpleSValBuilder.cpp
index 5d80251..197442b 100644
--- a/lib/StaticAnalyzer/Core/SimpleSValBuilder.cpp
+++ b/lib/StaticAnalyzer/Core/SimpleSValBuilder.cpp
@@ -97,7 +97,8 @@ SVal SimpleSValBuilder::evalCastFromNonLoc(NonLoc val, QualType castTy) {
return UnknownVal();
llvm::APSInt i = cast<nonloc::ConcreteInt>(val).getValue();
- i.setIsUnsigned(castTy->isUnsignedIntegerType() || Loc::isLocType(castTy));
+ i.setIsUnsigned(castTy->isUnsignedIntegerOrEnumerationType() ||
+ Loc::isLocType(castTy));
i = i.extOrTrunc(Context.getTypeSize(castTy));
if (isLocType)
@@ -129,7 +130,8 @@ SVal SimpleSValBuilder::evalCastFromLoc(Loc val, QualType castTy) {
return makeLocAsInteger(val, BitWidth);
llvm::APSInt i = cast<loc::ConcreteInt>(val).getValue();
- i.setIsUnsigned(castTy->isUnsignedIntegerType() || Loc::isLocType(castTy));
+ i.setIsUnsigned(castTy->isUnsignedIntegerOrEnumerationType() ||
+ Loc::isLocType(castTy));
i = i.extOrTrunc(BitWidth);
return makeIntVal(i);
}
diff --git a/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp b/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp
index fe6e1fd..b8dbb54 100644
--- a/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp
+++ b/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp
@@ -200,18 +200,20 @@ void AnalysisConsumer::HandleDeclContext(ASTContext &C, DeclContext *dc) {
}
break;
}
-
+
+ case Decl::ObjCCategoryImpl:
case Decl::ObjCImplementation: {
- ObjCImplementationDecl* ID = cast<ObjCImplementationDecl>(*I);
+ ObjCImplDecl* ID = cast<ObjCImplDecl>(*I);
HandleCode(ID);
- for (ObjCImplementationDecl::method_iterator MI = ID->meth_begin(),
+ for (ObjCContainerDecl::method_iterator MI = ID->meth_begin(),
ME = ID->meth_end(); MI != ME; ++MI) {
checkerMgr->runCheckersOnASTDecl(*MI, *Mgr, BR);
if ((*MI)->isThisDeclarationADefinition()) {
if (!Opts.AnalyzeSpecificFunction.empty() &&
- Opts.AnalyzeSpecificFunction != (*MI)->getSelector().getAsString())
+ Opts.AnalyzeSpecificFunction !=
+ (*MI)->getSelector().getAsString())
break;
DisplayFunction(*MI);
HandleCode(*MI);
@@ -232,6 +234,9 @@ void AnalysisConsumer::HandleTranslationUnit(ASTContext &C) {
checkerMgr->runCheckersOnASTDecl(TU, *Mgr, BR);
HandleDeclContext(C, TU);
+ // After all decls handled, run checkers on the entire TranslationUnit.
+ checkerMgr->runCheckersOnEndOfTranslationUnit(TU, *Mgr, BR);
+
// Explicitly destroy the PathDiagnosticClient. This will flush its output.
// FIXME: This should be replaced with something that doesn't rely on
// side-effects in PathDiagnosticClient's destructor. This is required when
diff --git a/lib/Tooling/CMakeLists.txt b/lib/Tooling/CMakeLists.txt
deleted file mode 100644
index f52cf6c..0000000
--- a/lib/Tooling/CMakeLists.txt
+++ /dev/null
@@ -1,6 +0,0 @@
-SET(LLVM_USED_LIBS clangBasic clangFrontend clangAST)
-
-add_clang_library(clangTooling
- JsonCompileCommandLineDatabase.cpp
- Tooling.cpp
- )
diff --git a/lib/Tooling/JsonCompileCommandLineDatabase.cpp b/lib/Tooling/JsonCompileCommandLineDatabase.cpp
deleted file mode 100644
index 7f027cf..0000000
--- a/lib/Tooling/JsonCompileCommandLineDatabase.cpp
+++ /dev/null
@@ -1,214 +0,0 @@
-//===--- JsonCompileCommandLineDatabase.cpp - Simple JSON database --------===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-//
-// This file implements reading a compile command line database, as written
-// out for example by CMake.
-//
-//===----------------------------------------------------------------------===//
-
-#include "JsonCompileCommandLineDatabase.h"
-#include "llvm/ADT/Twine.h"
-
-namespace clang {
-namespace tooling {
-
-namespace {
-
-// A parser for JSON escaped strings of command line arguments with \-escaping
-// for quoted arguments (see the documentation of UnescapeJsonCommandLine(...)).
-class CommandLineArgumentParser {
- public:
- CommandLineArgumentParser(llvm::StringRef CommandLine)
- : Input(CommandLine), Position(Input.begin()-1) {}
-
- std::vector<std::string> Parse() {
- bool HasMoreInput = true;
- while (HasMoreInput && NextNonWhitespace()) {
- std::string Argument;
- HasMoreInput = ParseStringInto(Argument);
- CommandLine.push_back(Argument);
- }
- return CommandLine;
- }
-
- private:
- // All private methods return true if there is more input available.
-
- bool ParseStringInto(std::string &String) {
- do {
- if (*Position == '"') {
- if (!ParseQuotedStringInto(String)) return false;
- } else {
- if (!ParseFreeStringInto(String)) return false;
- }
- } while (*Position != ' ');
- return true;
- }
-
- bool ParseQuotedStringInto(std::string &String) {
- if (!Next()) return false;
- while (*Position != '"') {
- if (!SkipEscapeCharacter()) return false;
- String.push_back(*Position);
- if (!Next()) return false;
- }
- return Next();
- }
-
- bool ParseFreeStringInto(std::string &String) {
- do {
- if (!SkipEscapeCharacter()) return false;
- String.push_back(*Position);
- if (!Next()) return false;
- } while (*Position != ' ' && *Position != '"');
- return true;
- }
-
- bool SkipEscapeCharacter() {
- if (*Position == '\\') {
- return Next();
- }
- return true;
- }
-
- bool NextNonWhitespace() {
- do {
- if (!Next()) return false;
- } while (*Position == ' ');
- return true;
- }
-
- bool Next() {
- ++Position;
- if (Position == Input.end()) return false;
- // Remove the JSON escaping first. This is done unconditionally.
- if (*Position == '\\') ++Position;
- return Position != Input.end();
- }
-
- const llvm::StringRef Input;
- llvm::StringRef::iterator Position;
- std::vector<std::string> CommandLine;
-};
-
-} // end namespace
-
-std::vector<std::string> UnescapeJsonCommandLine(
- llvm::StringRef JsonEscapedCommandLine) {
- CommandLineArgumentParser parser(JsonEscapedCommandLine);
- return parser.Parse();
-}
-
-JsonCompileCommandLineParser::JsonCompileCommandLineParser(
- const llvm::StringRef Input, CompileCommandHandler *CommandHandler)
- : Input(Input), Position(Input.begin()-1), CommandHandler(CommandHandler) {}
-
-bool JsonCompileCommandLineParser::Parse() {
- NextNonWhitespace();
- return ParseTranslationUnits();
-}
-
-std::string JsonCompileCommandLineParser::GetErrorMessage() const {
- return ErrorMessage;
-}
-
-bool JsonCompileCommandLineParser::ParseTranslationUnits() {
- if (!ConsumeOrError('[', "at start of compile command file")) return false;
- if (!ParseTranslationUnit(/*First=*/true)) return false;
- while (Consume(',')) {
- if (!ParseTranslationUnit(/*First=*/false)) return false;
- }
- if (!ConsumeOrError(']', "at end of array")) return false;
- if (CommandHandler != NULL) {
- CommandHandler->EndTranslationUnits();
- }
- return true;
-}
-
-bool JsonCompileCommandLineParser::ParseTranslationUnit(bool First) {
- if (First) {
- if (!Consume('{')) return true;
- } else {
- if (!ConsumeOrError('{', "at start of object")) return false;
- }
- if (!Consume('}')) {
- if (!ParseObjectKeyValuePairs()) return false;
- if (!ConsumeOrError('}', "at end of object")) return false;
- }
- if (CommandHandler != NULL) {
- CommandHandler->EndTranslationUnit();
- }
- return true;
-}
-
-bool JsonCompileCommandLineParser::ParseObjectKeyValuePairs() {
- do {
- llvm::StringRef Key;
- if (!ParseString(Key)) return false;
- if (!ConsumeOrError(':', "between name and value")) return false;
- llvm::StringRef Value;
- if (!ParseString(Value)) return false;
- if (CommandHandler != NULL) {
- CommandHandler->HandleKeyValue(Key, Value);
- }
- } while (Consume(','));
- return true;
-}
-
-bool JsonCompileCommandLineParser::ParseString(llvm::StringRef &String) {
- if (!ConsumeOrError('"', "at start of string")) return false;
- llvm::StringRef::iterator First = Position;
- llvm::StringRef::iterator Last = Position;
- while (!Consume('"')) {
- Consume('\\');
- ++Position;
- // We need to store Position, as Consume will change Last before leaving
- // the loop.
- Last = Position;
- }
- String = llvm::StringRef(First, Last - First);
- return true;
-}
-
-bool JsonCompileCommandLineParser::Consume(char C) {
- if (Position == Input.end()) return false;
- if (*Position != C) return false;
- NextNonWhitespace();
- return true;
-}
-
-bool JsonCompileCommandLineParser::ConsumeOrError(
- char C, llvm::StringRef Message) {
- if (!Consume(C)) {
- SetExpectError(C, Message);
- return false;
- }
- return true;
-}
-
-void JsonCompileCommandLineParser::SetExpectError(
- char C, llvm::StringRef Message) {
- ErrorMessage = (llvm::Twine("'") + llvm::StringRef(&C, 1) +
- "' expected " + Message + ".").str();
-}
-
-void JsonCompileCommandLineParser::NextNonWhitespace() {
- do {
- ++Position;
- } while (IsWhitespace());
-}
-
-bool JsonCompileCommandLineParser::IsWhitespace() {
- if (Position == Input.end()) return false;
- return (*Position == ' ' || *Position == '\t' ||
- *Position == '\n' || *Position == '\r');
-}
-
-} // end namespace tooling
-} // end namespace clang
diff --git a/lib/Tooling/JsonCompileCommandLineDatabase.h b/lib/Tooling/JsonCompileCommandLineDatabase.h
deleted file mode 100644
index 9e776d6..0000000
--- a/lib/Tooling/JsonCompileCommandLineDatabase.h
+++ /dev/null
@@ -1,107 +0,0 @@
-//===--- JsonCompileCommandLineDatabase - Simple JSON database --*- C++ -*-===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-//
-// This file implements reading a compile command line database, as written
-// out for example by CMake. It only supports the subset of the JSON standard
-// that is needed to parse the CMake output.
-// See http://www.json.org/ for the full standard.
-//
-//===----------------------------------------------------------------------===//
-
-#ifndef LLVM_CLANG_TOOLING_JSON_COMPILE_COMMAND_LINE_DATABASE_H
-#define LLVM_CLANG_TOOLING_JSON_COMPILE_COMMAND_LINE_DATABASE_H
-
-#include "llvm/ADT/StringRef.h"
-#include <string>
-#include <vector>
-
-namespace clang {
-namespace tooling {
-
-/// \brief Converts a JSON escaped command line to a vector of arguments.
-///
-/// \param JsonEscapedCommandLine The escaped command line as a string. This
-/// is assumed to be escaped as a JSON string (e.g. " and \ are escaped).
-/// In addition, any arguments containing spaces are assumed to be \-escaped
-///
-/// For example, the input (|| denoting non C-escaped strings):
-/// |./call a \"b \\\" c \\\\ \" d|
-/// would yield:
-/// [ |./call|, |a|, |b " c \ |, |d| ].
-std::vector<std::string> UnescapeJsonCommandLine(
- llvm::StringRef JsonEscapedCommandLine);
-
-/// \brief Interface for users of the JsonCompileCommandLineParser.
-class CompileCommandHandler {
- public:
- virtual ~CompileCommandHandler() {}
-
- /// \brief Called after all translation units are parsed.
- virtual void EndTranslationUnits() {}
-
- /// \brief Called at the end of a single translation unit.
- virtual void EndTranslationUnit() {}
-
- /// \brief Called for every (Key, Value) pair in a translation unit
- /// description.
- virtual void HandleKeyValue(llvm::StringRef Key, llvm::StringRef Value) {}
-};
-
-/// \brief A JSON parser that supports the subset of JSON needed to parse
-/// JSON compile command line databases as written out by CMake.
-///
-/// The supported subset describes a list of compile command lines for
-/// each processed translation unit. The translation units are stored in a
-/// JSON array, where each translation unit is described by a JSON object
-/// containing (Key, Value) pairs for the working directory the compile command
-/// line was executed from, the main C/C++ input file of the translation unit
-/// and the actual compile command line, for example:
-/// [
-/// {
-/// "file":"/file.cpp",
-/// "directory":"/",
-/// "command":"/cc /file.cpp"
-/// }
-/// ]
-class JsonCompileCommandLineParser {
- public:
- /// \brief Create a parser on 'Input', calling 'CommandHandler' to handle the
- /// parsed constructs. 'CommandHandler' may be NULL in order to just check
- /// the validity of 'Input'.
- JsonCompileCommandLineParser(const llvm::StringRef Input,
- CompileCommandHandler *CommandHandler);
-
- /// \brief Parses the specified input. Returns true if no parsing errors were
- /// foudn.
- bool Parse();
-
- /// \brief Returns an error message if Parse() returned false previously.
- std::string GetErrorMessage() const;
-
- private:
- bool ParseTranslationUnits();
- bool ParseTranslationUnit(bool First);
- bool ParseObjectKeyValuePairs();
- bool ParseString(llvm::StringRef &String);
- bool Consume(char C);
- bool ConsumeOrError(char C, llvm::StringRef Message);
- void NextNonWhitespace();
- bool IsWhitespace();
- void SetExpectError(char C, llvm::StringRef Message);
-
- const llvm::StringRef Input;
- llvm::StringRef::iterator Position;
- std::string ErrorMessage;
- CompileCommandHandler * const CommandHandler;
-};
-
-} // end namespace tooling
-} // end namespace clang
-
-#endif // LLVM_CLANG_TOOLING_JSON_COMPILE_COMMAND_LINE_DATABASE_H
diff --git a/lib/Tooling/Makefile b/lib/Tooling/Makefile
deleted file mode 100644
index 501a00c..0000000
--- a/lib/Tooling/Makefile
+++ /dev/null
@@ -1,15 +0,0 @@
-##===- clang/lib/Tooling/Makefile ---------------------------*- Makefile -*-===##
-#
-# The LLVM Compiler Infrastructure
-#
-# This file is distributed under the University of Illinois Open Source
-# License. See LICENSE.TXT for details.
-#
-##===----------------------------------------------------------------------===##
-
-CLANG_LEVEL := ../..
-LIBRARYNAME := clangTooling
-
-include $(CLANG_LEVEL)/Makefile
-
-
diff --git a/lib/Tooling/Tooling.cpp b/lib/Tooling/Tooling.cpp
deleted file mode 100644
index c1714a9..0000000
--- a/lib/Tooling/Tooling.cpp
+++ /dev/null
@@ -1,322 +0,0 @@
-//===--- Tooling.cpp - Running clang standalone tools --------------------===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-//
-// This file implements functions to run clang tools standalone instead
-// of running them as a plugin.
-//
-//===----------------------------------------------------------------------===//
-
-#include "clang/Tooling/Tooling.h"
-#include "llvm/ADT/ArrayRef.h"
-#include "llvm/ADT/SmallString.h"
-#include "llvm/Support/CommandLine.h"
-#include "llvm/Support/Host.h"
-#include "llvm/Support/MemoryBuffer.h"
-#include "llvm/Support/ManagedStatic.h"
-#include "llvm/Support/Path.h"
-#include "llvm/Support/raw_ostream.h"
-#include "clang/Basic/DiagnosticIDs.h"
-#include "clang/Driver/Compilation.h"
-#include "clang/Driver/Driver.h"
-#include "clang/Driver/Tool.h"
-#include "clang/Frontend/CompilerInstance.h"
-#include "clang/Frontend/FrontendAction.h"
-#include "clang/Frontend/FrontendDiagnostic.h"
-#include "clang/Frontend/TextDiagnosticPrinter.h"
-#include "JsonCompileCommandLineDatabase.h"
-#include <map>
-#include <cstdio>
-
-namespace clang {
-namespace tooling {
-
-namespace {
-
-// Checks that the input conforms to the argv[] convention as in
-// main(). Namely:
-// - it must contain at least a program path,
-// - argv[0], ..., and argv[argc - 1] mustn't be NULL, and
-// - argv[argc] must be NULL.
-void ValidateArgv(int argc, char* argv[]) {
- if (argc < 1) {
- fprintf(stderr, "ERROR: argc is %d. It must be >= 1.\n", argc);
- abort();
- }
-
- for (int i = 0; i < argc; ++i) {
- if (argv[i] == NULL) {
- fprintf(stderr, "ERROR: argv[%d] is NULL.\n", i);
- abort();
- }
- }
-
- if (argv[argc] != NULL) {
- fprintf(stderr, "ERROR: argv[argc] isn't NULL.\n");
- abort();
- }
-}
-
-} // end namespace
-
-// FIXME: This file contains structural duplication with other parts of the
-// code that sets up a compiler to run tools on it, and we should refactor
-// it to be based on the same framework.
-
-static clang::Diagnostic* NewTextDiagnostics() {
- llvm::IntrusiveRefCntPtr<clang::DiagnosticIDs> DiagIDs(
- new clang::DiagnosticIDs());
- clang::TextDiagnosticPrinter *DiagClient = new clang::TextDiagnosticPrinter(
- llvm::errs(), clang::DiagnosticOptions());
- return new clang::Diagnostic(DiagIDs, DiagClient);
-}
-
-// Exists solely for the purpose of lookup of the main executable.
-static int StaticSymbol;
-
-/// \brief Builds a clang driver initialized for running clang tools.
-static clang::driver::Driver* NewDriver(clang::Diagnostic* Diagnostics,
- const char* BinaryName) {
- // This just needs to be some symbol in the binary.
- void* const SymbolAddr = &StaticSymbol;
- const llvm::sys::Path ExePath =
- llvm::sys::Path::GetMainExecutable(BinaryName, SymbolAddr);
-
- const std::string DefaultOutputName = "a.out";
- clang::driver::Driver* CompilerDriver = new clang::driver::Driver(
- ExePath.str(), llvm::sys::getHostTriple(),
- DefaultOutputName, false, false, *Diagnostics);
- CompilerDriver->setTitle("clang_based_tool");
- return CompilerDriver;
-}
-
-/// \brief Retrieves the clang CC1 specific flags out of the compilation's jobs.
-/// Returns NULL on error.
-static const clang::driver::ArgStringList* GetCC1Arguments(
- clang::Diagnostic* Diagnostics, clang::driver::Compilation* Compilation) {
- // We expect to get back exactly one Command job, if we didn't something
- // failed. Extract that job from the Compilation.
- const clang::driver::JobList &Jobs = Compilation->getJobs();
- if (Jobs.size() != 1 || !isa<clang::driver::Command>(*Jobs.begin())) {
- llvm::SmallString<256> error_msg;
- llvm::raw_svector_ostream error_stream(error_msg);
- Compilation->PrintJob(error_stream, Compilation->getJobs(), "; ", true);
- Diagnostics->Report(clang::diag::err_fe_expected_compiler_job)
- << error_stream.str();
- return NULL;
- }
-
- // The one job we find should be to invoke clang again.
- const clang::driver::Command *Cmd =
- cast<clang::driver::Command>(*Jobs.begin());
- if (llvm::StringRef(Cmd->getCreator().getName()) != "clang") {
- Diagnostics->Report(clang::diag::err_fe_expected_clang_command);
- return NULL;
- }
-
- return &Cmd->getArguments();
-}
-
-/// \brief Returns a clang build invocation initialized from the CC1 flags.
-static clang::CompilerInvocation* NewInvocation(
- clang::Diagnostic* Diagnostics,
- const clang::driver::ArgStringList& CC1Args) {
- clang::CompilerInvocation* Invocation = new clang::CompilerInvocation;
- clang::CompilerInvocation::CreateFromArgs(
- *Invocation, CC1Args.data(), CC1Args.data() + CC1Args.size(),
- *Diagnostics);
- Invocation->getFrontendOpts().DisableFree = false;
- return Invocation;
-}
-
-/// \brief Runs the specified clang tool action and returns whether it executed
-/// successfully.
-static bool RunInvocation(const char* BinaryName,
- clang::driver::Compilation* Compilation,
- clang::CompilerInvocation* Invocation,
- const clang::driver::ArgStringList& CC1Args,
- clang::FrontendAction* ToolAction) {
- llvm::OwningPtr<clang::FrontendAction> ScopedToolAction(ToolAction);
- // Show the invocation, with -v.
- if (Invocation->getHeaderSearchOpts().Verbose) {
- llvm::errs() << "clang Invocation:\n";
- Compilation->PrintJob(llvm::errs(), Compilation->getJobs(), "\n", true);
- llvm::errs() << "\n";
- }
-
- // Create a compiler instance to handle the actual work.
- clang::CompilerInstance Compiler;
- Compiler.setInvocation(Invocation);
-
- // Create the compilers actual diagnostics engine.
- Compiler.createDiagnostics(CC1Args.size(),
- const_cast<char**>(CC1Args.data()));
- if (!Compiler.hasDiagnostics())
- return false;
-
- // Infer the builtin include path if unspecified.
- if (Compiler.getHeaderSearchOpts().UseBuiltinIncludes &&
- Compiler.getHeaderSearchOpts().ResourceDir.empty()) {
- // This just needs to be some symbol in the binary.
- void* const SymbolAddr = &StaticSymbol;
- Compiler.getHeaderSearchOpts().ResourceDir =
- clang::CompilerInvocation::GetResourcesPath(BinaryName, SymbolAddr);
- }
-
- const bool Success = Compiler.ExecuteAction(*ToolAction);
- return Success;
-}
-
-/// \brief Converts a string vector representing a Command line into a C
-/// string vector representing the Argv (including the trailing NULL).
-std::vector<char*> CommandLineToArgv(const std::vector<std::string>* Command) {
- std::vector<char*> Result(Command->size() + 1);
- for (std::vector<char*>::size_type I = 0; I < Command->size(); ++I) {
- Result[I] = const_cast<char*>((*Command)[I].c_str());
- }
- Result[Command->size()] = NULL;
- return Result;
-}
-
-bool RunToolWithFlags(
- clang::FrontendAction* ToolAction, int Args, char* Argv[]) {
- ValidateArgv(Args, Argv);
- const llvm::OwningPtr<clang::Diagnostic> Diagnostics(NewTextDiagnostics());
- const llvm::OwningPtr<clang::driver::Driver> Driver(
- NewDriver(Diagnostics.get(), Argv[0]));
- const llvm::OwningPtr<clang::driver::Compilation> Compilation(
- Driver->BuildCompilation(llvm::ArrayRef<const char*>(Argv, Args)));
- const clang::driver::ArgStringList* const CC1Args = GetCC1Arguments(
- Diagnostics.get(), Compilation.get());
- if (CC1Args == NULL) {
- return false;
- }
- llvm::OwningPtr<clang::CompilerInvocation> Invocation(
- NewInvocation(Diagnostics.get(), *CC1Args));
- return RunInvocation(Argv[0], Compilation.get(), Invocation.take(),
- *CC1Args, ToolAction);
-}
-
-/// \brief Runs 'ToolAction' on the code specified by 'FileContents'.
-///
-/// \param FileContents A mapping from file name to source code. For each
-/// entry a virtual file mapping will be created when running the tool.
-bool RunToolWithFlagsOnCode(
- const std::vector<std::string>& CommandLine,
- const std::map<std::string, std::string>& FileContents,
- clang::FrontendAction* ToolAction) {
- const std::vector<char*> Argv = CommandLineToArgv(&CommandLine);
- const char* const BinaryName = Argv[0];
-
- const llvm::OwningPtr<clang::Diagnostic> Diagnostics(NewTextDiagnostics());
- const llvm::OwningPtr<clang::driver::Driver> Driver(
- NewDriver(Diagnostics.get(), BinaryName));
-
- // Since the Input is only virtual, don't check whether it exists.
- Driver->setCheckInputsExist(false);
-
- const llvm::OwningPtr<clang::driver::Compilation> Compilation(
- Driver->BuildCompilation(llvm::ArrayRef<const char*>(&Argv[0],
- Argv.size() - 1)));
- const clang::driver::ArgStringList* const CC1Args = GetCC1Arguments(
- Diagnostics.get(), Compilation.get());
- if (CC1Args == NULL) {
- return false;
- }
- llvm::OwningPtr<clang::CompilerInvocation> Invocation(
- NewInvocation(Diagnostics.get(), *CC1Args));
-
- for (std::map<std::string, std::string>::const_iterator
- It = FileContents.begin(), End = FileContents.end();
- It != End; ++It) {
- // Inject the code as the given file name into the preprocessor options.
- const llvm::MemoryBuffer* Input =
- llvm::MemoryBuffer::getMemBuffer(It->second.c_str());
- Invocation->getPreprocessorOpts().addRemappedFile(It->first.c_str(), Input);
- }
-
- return RunInvocation(BinaryName, Compilation.get(),
- Invocation.take(), *CC1Args, ToolAction);
-}
-
-bool RunSyntaxOnlyToolOnCode(
- clang::FrontendAction *ToolAction, llvm::StringRef Code) {
- const char* const FileName = "input.cc";
- const char* const CommandLine[] = {
- "clang-tool", "-fsyntax-only", FileName
- };
- std::map<std::string, std::string> FileContents;
- FileContents[FileName] = Code;
- return RunToolWithFlagsOnCode(
- std::vector<std::string>(
- CommandLine,
- CommandLine + sizeof(CommandLine)/sizeof(CommandLine[0])),
- FileContents, ToolAction);
-}
-
-namespace {
-
-// A CompileCommandHandler implementation that finds compile commands for a
-// specific input file.
-//
-// FIXME: Implement early exit when JsonCompileCommandLineParser supports it.
-class FindHandler : public clang::tooling::CompileCommandHandler {
- public:
- explicit FindHandler(llvm::StringRef File)
- : FileToMatch(File), FoundMatchingCommand(false) {}
-
- virtual void EndTranslationUnits() {
- if (!FoundMatchingCommand && ErrorMessage.empty()) {
- ErrorMessage = "ERROR: No matching command found.";
- }
- }
-
- virtual void EndTranslationUnit() {
- if (File == FileToMatch) {
- FoundMatchingCommand = true;
- MatchingCommand.Directory = Directory;
- MatchingCommand.CommandLine = UnescapeJsonCommandLine(Command);
- }
- }
-
- virtual void HandleKeyValue(llvm::StringRef Key, llvm::StringRef Value) {
- if (Key == "directory") { Directory = Value; }
- else if (Key == "file") { File = Value; }
- else if (Key == "command") { Command = Value; }
- else {
- ErrorMessage = (llvm::Twine("Unknown key: \"") + Key + "\"").str();
- }
- }
-
- const llvm::StringRef FileToMatch;
- bool FoundMatchingCommand;
- CompileCommand MatchingCommand;
- std::string ErrorMessage;
-
- llvm::StringRef Directory;
- llvm::StringRef File;
- llvm::StringRef Command;
-};
-
-} // end namespace
-
-CompileCommand FindCompileArgsInJsonDatabase(
- llvm::StringRef FileName, llvm::StringRef JsonDatabase,
- std::string &ErrorMessage) {
- FindHandler find_handler(FileName);
- JsonCompileCommandLineParser parser(JsonDatabase, &find_handler);
- if (!parser.Parse()) {
- ErrorMessage = parser.GetErrorMessage();
- return CompileCommand();
- }
- return find_handler.MatchingCommand;
-}
-
-} // end namespace tooling
-} // end namespace clang
-
diff --git a/test/Analysis/CFNumber.c b/test/Analysis/CFNumber.c
index dd57cd9..11af0747 100644
--- a/test/Analysis/CFNumber.c
+++ b/test/Analysis/CFNumber.c
@@ -22,10 +22,15 @@ CFNumberRef f1(unsigned char x) {
return CFNumberCreate(0, kCFNumberSInt16Type, &x); // expected-warning{{An 8 bit integer is used to initialize a CFNumber object that represents a 16 bit integer. 8 bits of the CFNumber value will be garbage.}}
}
-CFNumberRef f2(unsigned short x) {
+__attribute__((cf_returns_retained)) CFNumberRef f2(unsigned short x) {
return CFNumberCreate(0, kCFNumberSInt8Type, &x); // expected-warning{{A 16 bit integer is used to initialize a CFNumber object that represents an 8 bit integer. 8 bits of the input integer will be lost.}}
}
+// test that the attribute overrides the naming convention.
+__attribute__((cf_returns_not_retained)) CFNumberRef CreateNum(unsigned char x) {
+ return CFNumberCreate(0, kCFNumberSInt8Type, &x); // expected-warning{{leak}}
+}
+
CFNumberRef f3(unsigned i) {
return CFNumberCreate(0, kCFNumberLongType, &i); // expected-warning{{A 32 bit integer is used to initialize a CFNumber object that represents a 64 bit integer.}}
}
diff --git a/test/Analysis/bstring.c b/test/Analysis/bstring.c
index 1f6839d..68bbb1a 100644
--- a/test/Analysis/bstring.c
+++ b/test/Analysis/bstring.c
@@ -136,13 +136,38 @@ void memcpy13() {
memcpy(a, 0, 0); // no-warning
}
+void memcpy_unknown_size (size_t n) {
+ char a[4], b[4] = {1};
+ if (memcpy(a, b, n) != a)
+ (void)*(char*)0; // no-warning
+}
+
+void memcpy_unknown_size_warn (size_t n) {
+ char a[4];
+ if (memcpy(a, 0, n) != a) // expected-warning{{Null pointer argument in call to byte string function}}
+ (void)*(char*)0; // no-warning
+}
+
//===----------------------------------------------------------------------===
// mempcpy()
//===----------------------------------------------------------------------===
+#ifdef VARIANT
+
+#define __mempcpy_chk BUILTIN(__mempcpy_chk)
+void *__mempcpy_chk(void *restrict s1, const void *restrict s2, size_t n,
+ size_t destlen);
+
+#define mempcpy(a,b,c) __mempcpy_chk(a,b,c,(size_t)-1)
+
+#else /* VARIANT */
+
#define mempcpy BUILTIN(mempcpy)
void *mempcpy(void *restrict s1, const void *restrict s2, size_t n);
+#endif /* VARIANT */
+
+
void mempcpy0 () {
char src[] = {1, 2, 3, 4};
char dst[5] = {0};
@@ -233,6 +258,18 @@ void mempcpy13() {
mempcpy(a, 0, 0); // no-warning
}
+void mempcpy_unknown_size_warn (size_t n) {
+ char a[4];
+ if (mempcpy(a, 0, n) != a) // expected-warning{{Null pointer argument in call to byte string function}}
+ (void)*(char*)0; // no-warning
+}
+
+void mempcpy_unknownable_size (char *src, float n) {
+ char a[4];
+ // This used to crash because we don't model floats.
+ mempcpy(a, src, (size_t)n);
+}
+
//===----------------------------------------------------------------------===
// memmove()
//===----------------------------------------------------------------------===
diff --git a/test/Analysis/misc-ps-cxx0x.cpp b/test/Analysis/misc-ps-cxx0x.cpp
new file mode 100644
index 0000000..f21e82c
--- /dev/null
+++ b/test/Analysis/misc-ps-cxx0x.cpp
@@ -0,0 +1,11 @@
+// RUN: %clang --analyze -std=c++0x %s -Xclang -verify
+
+void test_static_assert() {
+ static_assert(sizeof(void *) == sizeof(void*), "test_static_assert");
+}
+
+void test_analyzer_working() {
+ int *p = 0;
+ *p = 0xDEADBEEF; // expected-warning {{null}}
+}
+
diff --git a/test/Analysis/misc-ps-region-store.cpp b/test/Analysis/misc-ps-region-store.cpp
index b122bff..7959359 100644
--- a/test/Analysis/misc-ps-region-store.cpp
+++ b/test/Analysis/misc-ps-region-store.cpp
@@ -395,3 +395,22 @@ unsigned test_invalidate_in_ctor_new() {
return x; // no-warning
}
+// Test assigning into a symbolic offset.
+struct TestAssignIntoSymbolicOffset {
+ int **stuff[100];
+ void test(int x, int y);
+};
+
+void TestAssignIntoSymbolicOffset::test(int x, int y) {
+ x--;
+ if (x > 8 || x < 0)
+ return;
+ if (stuff[x])
+ return;
+ if (!stuff[x]) {
+ stuff[x] = new int*[y+1];
+ // Previously triggered a null dereference.
+ stuff[x][y] = 0; // no-warning
+ }
+}
+
diff --git a/test/Analysis/misc-ps-region-store.m b/test/Analysis/misc-ps-region-store.m
index be0356d..27f12c9 100644
--- a/test/Analysis/misc-ps-region-store.m
+++ b/test/Analysis/misc-ps-region-store.m
@@ -1299,3 +1299,27 @@ RDar9163742_Rect RDar9163742_IntegralRect(RDar9163742_Rect frame)
return RDar9163742_RectIntegral(integralFrame); // no-warning; all fields initialized
}
+// Test correct handling of prefix '--' operator.
+void rdar9444714() {
+ int x;
+ char str[ 32 ];
+ char buf[ 32 ];
+ char * dst;
+ char * ptr;
+
+ x = 1234;
+ dst = str;
+ ptr = buf;
+ do
+ {
+ *ptr++ = (char)( '0' + ( x % 10 ) );
+ x /= 10;
+ } while( x > 0 );
+
+ while( ptr > buf )
+ {
+ *dst++ = *( --( ptr ) ); // no-warning
+ }
+ *dst = '\0';
+}
+
diff --git a/test/Analysis/misc-ps.c b/test/Analysis/misc-ps.c
new file mode 100644
index 0000000..bef5b06
--- /dev/null
+++ b/test/Analysis/misc-ps.c
@@ -0,0 +1,83 @@
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -analyze -disable-free -analyzer-eagerly-assume -analyzer-checker=core -analyzer-checker=deadcode -verify %s
+
+unsigned long strlen(const char *);
+
+int size_rdar9373039 = 1;
+int rdar9373039() {
+ int x;
+ int j = 0;
+
+ for (int i = 0 ; i < size_rdar9373039 ; ++i)
+ x = 1;
+
+ // strlen doesn't invalidate the value of 'size_rdar9373039'.
+ int extra = (2 + strlen ("Clang") + ((4 - ((unsigned int) (2 + strlen ("Clang")) % 4)) % 4)) + (2 + strlen ("1.0") + ((4 - ((unsigned int) (2 + strlen ("1.0")) % 4)) % 4));
+
+ for (int i = 0 ; i < size_rdar9373039 ; ++i)
+ j += x; // no-warning
+
+ return j;
+}
+
+int foo_rdar9373039(const char *);
+
+int rdar93730392() {
+ int x;
+ int j = 0;
+
+ for (int i = 0 ; i < size_rdar9373039 ; ++i)
+ x = 1;
+
+ int extra = (2 + foo_rdar9373039 ("Clang") + ((4 - ((unsigned int) (2 + foo_rdar9373039 ("Clang")) % 4)) % 4)) + (2 + foo_rdar9373039 ("1.0") + ((4 - ((unsigned int) (2 + foo_rdar9373039 ("1.0")) % 4)) % 4)); // expected-warning {{never read}}
+
+ for (int i = 0 ; i < size_rdar9373039 ; ++i)
+ j += x; // expected-warning {{garbage}}
+
+ return j;
+}
+
+
+int PR8962 (int *t) {
+ // This should look through the __extension__ no-op.
+ if (__extension__ (t)) return 0;
+ return *t; // expected-warning {{null pointer}}
+}
+
+int PR8962_b (int *t) {
+ // This should still ignore the nested casts
+ // which aren't handled by a single IgnoreParens()
+ if (((int)((int)t))) return 0;
+ return *t; // expected-warning {{null pointer}}
+}
+
+int PR8962_c (int *t) {
+ // If the last element in a StmtExpr was a ParenExpr, it's still live
+ if (({ (t ? (_Bool)0 : (_Bool)1); })) return 0;
+ return *t; // no-warning
+}
+
+int PR8962_d (int *t) {
+ // If the last element in a StmtExpr is an __extension__, it's still live
+ if (({ __extension__(t ? (_Bool)0 : (_Bool)1); })) return 0;
+ return *t; // no-warning
+}
+
+int PR8962_e (int *t) {
+ // Redundant casts can mess things up!
+ // Environment used to skip through NoOp casts, but LiveVariables didn't!
+ if (({ (t ? (int)(int)0L : (int)(int)1L); })) return 0;
+ return *t; // no-warning
+}
+
+int PR8962_f (int *t) {
+ // The StmtExpr isn't a block-level expression here,
+ // the __extension__ is. But the value should be attached to the StmtExpr
+ // anyway. Make sure the block-level check is /before/ IgnoreParens.
+ if ( __extension__({
+ _Bool r;
+ if (t) r = 0;
+ else r = 1;
+ r;
+ }) ) return 0;
+ return *t; // no-warning
+}
diff --git a/test/Analysis/misc-ps.m b/test/Analysis/misc-ps.m
index 9de4afb..da84b24 100644
--- a/test/Analysis/misc-ps.m
+++ b/test/Analysis/misc-ps.m
@@ -1301,3 +1301,28 @@ static void test(unsigned int bit_mask)
}
}
}
+
+// Don't crash on code containing __label__.
+int radar9414427_aux();
+void radar9414427() {
+ __label__ mylabel;
+ if (radar9414427_aux()) {
+ mylabel: do {}
+ while (0);
+ }
+}
+
+// Analyze methods in @implementation (category)
+@interface RDar9465344
+@end
+
+@implementation RDar9465344 (MyCategory)
+- (void) testcategoryImpl {
+ int *p = 0x0;
+ *p = 0xDEADBEEF; // expected-warning {{null}}
+}
+@end
+
+@implementation RDar9465344
+@end
+
diff --git a/test/Analysis/plist-output-alternate.m b/test/Analysis/plist-output-alternate.m
index a7e3c3c..0f4d3ae 100644
--- a/test/Analysis/plist-output-alternate.m
+++ b/test/Analysis/plist-output-alternate.m
@@ -864,9 +864,9 @@ void rdar8331641(int x) {
// CHECK: </array>
// CHECK: </array>
// CHECK: <key>extended_message</key>
-// CHECK: <string>Call to function &apos;CFNumberCreate&apos; returns a Core Foundation object with a +1 retain count (owning reference)</string>
+// CHECK: <string>Call to function &apos;CFNumberCreate&apos; returns a Core Foundation object with a +1 retain count</string>
// CHECK: <key>message</key>
-// CHECK: <string>Call to function &apos;CFNumberCreate&apos; returns a Core Foundation object with a +1 retain count (owning reference)</string>
+// CHECK: <string>Call to function &apos;CFNumberCreate&apos; returns a Core Foundation object with a +1 retain count</string>
// CHECK: </dict>
// CHECK: <dict>
// CHECK: <key>kind</key><string>control</string>
@@ -994,9 +994,9 @@ void rdar8331641(int x) {
// CHECK: </array>
// CHECK: </array>
// CHECK: <key>extended_message</key>
-// CHECK: <string>Object allocated on line 53 and stored into &apos;value&apos; is not referenced later in this execution path and has a retain count of +1 (object leaked)</string>
+// CHECK: <string>Object leaked: object allocated and stored into &apos;value&apos; is not referenced later in this execution path and has a retain count of +1</string>
// CHECK: <key>message</key>
-// CHECK: <string>Object allocated on line 53 and stored into &apos;value&apos; is not referenced later in this execution path and has a retain count of +1 (object leaked)</string>
+// CHECK: <string>Object leaked: object allocated and stored into &apos;value&apos; is not referenced later in this execution path and has a retain count of +1</string>
// CHECK: </dict>
// CHECK: </array>
// CHECK: <key>description</key><string>Potential leak of an object allocated on line 53 and stored into &apos;value&apos;</string>
@@ -1012,3 +1012,4 @@ void rdar8331641(int x) {
// CHECK: </array>
// CHECK: </dict>
// CHECK: </plist>
+
diff --git a/test/Analysis/retain-release.m b/test/Analysis/retain-release.m
index 6782c90..7af14f1 100644
--- a/test/Analysis/retain-release.m
+++ b/test/Analysis/retain-release.m
@@ -280,7 +280,7 @@ CFAbsoluteTime f1() {
CFRelease(date);
CFDateGetAbsoluteTime(date); // no-warning
CFRelease(date);
- t = CFDateGetAbsoluteTime(date); // expected-warning{{Reference-counted object is used after it is released.}}
+ t = CFDateGetAbsoluteTime(date); // expected-warning{{Reference-counted object is used after it is released}}
return t;
}
@@ -291,7 +291,7 @@ CFAbsoluteTime f2() {
CFRelease(date);
CFDateGetAbsoluteTime(date); // no-warning
[((NSDate*) date) release];
- t = CFDateGetAbsoluteTime(date); // expected-warning{{Reference-counted object is used after it is released.}}
+ t = CFDateGetAbsoluteTime(date); // expected-warning{{Reference-counted object is used after it is released}}
return t;
}
@@ -343,7 +343,7 @@ CFDateRef f6(int x) {
CFDateRef f7() {
CFDateRef date = CFDateCreate(0, CFAbsoluteTimeGetCurrent()); //expected-warning{{leak}}
CFRetain(date);
- date = CFDateCreate(0, CFAbsoluteTimeGetCurrent());
+ date = CFDateCreate(0, CFAbsoluteTimeGetCurrent()); // expected-warning {{leak}}
return date;
}
@@ -357,8 +357,8 @@ CFDateRef f8() {
return date;
}
-CFDateRef f9() {
- CFDateRef date = CFDateCreate(0, CFAbsoluteTimeGetCurrent());
+__attribute__((cf_returns_retained)) CFDateRef f9() {
+ CFDateRef date = CFDateCreate(0, CFAbsoluteTimeGetCurrent()); // no-warning
int *p = 0;
// When allocations fail, CFDateCreate can return null.
if (!date) *p = 1; // expected-warning{{null}}
diff --git a/test/Analysis/retain-release.mm b/test/Analysis/retain-release.mm
new file mode 100644
index 0000000..0faeb1a
--- /dev/null
+++ b/test/Analysis/retain-release.mm
@@ -0,0 +1,306 @@
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -analyze -analyzer-checker=core,osx.coreFoundation.CFRetainRelease,osx.cocoa.ClassRelease -analyzer-store=region -fblocks -verify %s
+
+#if __has_feature(attribute_ns_returns_retained)
+#define NS_RETURNS_RETAINED __attribute__((ns_returns_retained))
+#endif
+#if __has_feature(attribute_cf_returns_retained)
+#define CF_RETURNS_RETAINED __attribute__((cf_returns_retained))
+#endif
+#if __has_feature(attribute_ns_returns_not_retained)
+#define NS_RETURNS_NOT_RETAINED __attribute__((ns_returns_not_retained))
+#endif
+#if __has_feature(attribute_cf_returns_not_retained)
+#define CF_RETURNS_NOT_RETAINED __attribute__((cf_returns_not_retained))
+#endif
+#if __has_feature(attribute_ns_consumes_self)
+#define NS_CONSUMES_SELF __attribute__((ns_consumes_self))
+#endif
+#if __has_feature(attribute_ns_consumed)
+#define NS_CONSUMED __attribute__((ns_consumed))
+#endif
+#if __has_feature(attribute_cf_consumed)
+#define CF_CONSUMED __attribute__((cf_consumed))
+#endif
+
+//===----------------------------------------------------------------------===//
+// The following code is reduced using delta-debugging from Mac OS X headers:
+//
+// #include <Cocoa/Cocoa.h>
+// #include <CoreFoundation/CoreFoundation.h>
+// #include <DiskArbitration/DiskArbitration.h>
+// #include <QuartzCore/QuartzCore.h>
+// #include <Quartz/Quartz.h>
+// #include <IOKit/IOKitLib.h>
+//
+// It includes the basic definitions for the test cases below.
+//===----------------------------------------------------------------------===//
+
+typedef unsigned int __darwin_natural_t;
+typedef unsigned long uintptr_t;
+typedef unsigned int uint32_t;
+typedef unsigned long long uint64_t;
+typedef unsigned int UInt32;
+typedef signed long CFIndex;
+typedef struct {
+ CFIndex location;
+ CFIndex length;
+} CFRange;
+static __inline__ __attribute__((always_inline)) CFRange CFRangeMake(CFIndex loc, CFIndex len) {
+ CFRange range;
+ range.location = loc;
+ range.length = len;
+ return range;
+}
+typedef const void * CFTypeRef;
+typedef const struct __CFString * CFStringRef;
+typedef const struct __CFAllocator * CFAllocatorRef;
+extern const CFAllocatorRef kCFAllocatorDefault;
+extern CFTypeRef CFRetain(CFTypeRef cf);
+extern void CFRelease(CFTypeRef cf);
+typedef struct {
+}
+CFArrayCallBacks;
+extern const CFArrayCallBacks kCFTypeArrayCallBacks;
+typedef const struct __CFArray * CFArrayRef;
+typedef struct __CFArray * CFMutableArrayRef;
+extern CFMutableArrayRef CFArrayCreateMutable(CFAllocatorRef allocator, CFIndex capacity, const CFArrayCallBacks *callBacks);
+extern const void *CFArrayGetValueAtIndex(CFArrayRef theArray, CFIndex idx);
+extern void CFArrayAppendValue(CFMutableArrayRef theArray, const void *value);
+typedef struct {
+}
+CFDictionaryKeyCallBacks;
+extern const CFDictionaryKeyCallBacks kCFTypeDictionaryKeyCallBacks;
+typedef struct {
+}
+CFDictionaryValueCallBacks;
+extern const CFDictionaryValueCallBacks kCFTypeDictionaryValueCallBacks;
+typedef const struct __CFDictionary * CFDictionaryRef;
+typedef struct __CFDictionary * CFMutableDictionaryRef;
+extern CFMutableDictionaryRef CFDictionaryCreateMutable(CFAllocatorRef allocator, CFIndex capacity, const CFDictionaryKeyCallBacks *keyCallBacks, const CFDictionaryValueCallBacks *valueCallBacks);
+typedef UInt32 CFStringEncoding;
+enum {
+kCFStringEncodingMacRoman = 0, kCFStringEncodingWindowsLatin1 = 0x0500, kCFStringEncodingISOLatin1 = 0x0201, kCFStringEncodingNextStepLatin = 0x0B01, kCFStringEncodingASCII = 0x0600, kCFStringEncodingUnicode = 0x0100, kCFStringEncodingUTF8 = 0x08000100, kCFStringEncodingNonLossyASCII = 0x0BFF , kCFStringEncodingUTF16 = 0x0100, kCFStringEncodingUTF16BE = 0x10000100, kCFStringEncodingUTF16LE = 0x14000100, kCFStringEncodingUTF32 = 0x0c000100, kCFStringEncodingUTF32BE = 0x18000100, kCFStringEncodingUTF32LE = 0x1c000100 };
+extern CFStringRef CFStringCreateWithCString(CFAllocatorRef alloc, const char *cStr, CFStringEncoding encoding);
+typedef double CFTimeInterval;
+typedef CFTimeInterval CFAbsoluteTime;
+extern CFAbsoluteTime CFAbsoluteTimeGetCurrent(void);
+typedef const struct __CFDate * CFDateRef;
+extern CFDateRef CFDateCreate(CFAllocatorRef allocator, CFAbsoluteTime at);
+extern CFAbsoluteTime CFDateGetAbsoluteTime(CFDateRef theDate);
+typedef __darwin_natural_t natural_t;
+typedef natural_t mach_port_name_t;
+typedef mach_port_name_t mach_port_t;
+typedef int kern_return_t;
+typedef kern_return_t mach_error_t;
+enum {
+kCFNumberSInt8Type = 1, kCFNumberSInt16Type = 2, kCFNumberSInt32Type = 3, kCFNumberSInt64Type = 4, kCFNumberFloat32Type = 5, kCFNumberFloat64Type = 6, kCFNumberCharType = 7, kCFNumberShortType = 8, kCFNumberIntType = 9, kCFNumberLongType = 10, kCFNumberLongLongType = 11, kCFNumberFloatType = 12, kCFNumberDoubleType = 13, kCFNumberCFIndexType = 14, kCFNumberNSIntegerType = 15, kCFNumberCGFloatType = 16, kCFNumberMaxType = 16 };
+typedef CFIndex CFNumberType;
+typedef const struct __CFNumber * CFNumberRef;
+extern CFNumberRef CFNumberCreate(CFAllocatorRef allocator, CFNumberType theType, const void *valuePtr);
+typedef const struct __CFAttributedString *CFAttributedStringRef;
+typedef struct __CFAttributedString *CFMutableAttributedStringRef;
+extern CFAttributedStringRef CFAttributedStringCreate(CFAllocatorRef alloc, CFStringRef str, CFDictionaryRef attributes) ;
+extern CFMutableAttributedStringRef CFAttributedStringCreateMutableCopy(CFAllocatorRef alloc, CFIndex maxLength, CFAttributedStringRef aStr) ;
+extern void CFAttributedStringSetAttribute(CFMutableAttributedStringRef aStr, CFRange range, CFStringRef attrName, CFTypeRef value) ;
+typedef signed char BOOL;
+typedef unsigned long NSUInteger;
+@class NSString, Protocol;
+extern void NSLog(NSString *format, ...) __attribute__((format(__NSString__, 1, 2)));
+typedef struct _NSZone NSZone;
+@class NSInvocation, NSMethodSignature, NSCoder, NSString, NSEnumerator;
+@protocol NSObject
+- (BOOL)isEqual:(id)object;
+- (id)retain;
+- (oneway void)release;
+- (id)autorelease;
+@end @protocol NSCopying - (id)copyWithZone:(NSZone *)zone;
+@end @protocol NSMutableCopying - (id)mutableCopyWithZone:(NSZone *)zone;
+@end @protocol NSCoding - (void)encodeWithCoder:(NSCoder *)aCoder;
+@end
+@interface NSObject <NSObject> {}
++ (id)allocWithZone:(NSZone *)zone;
++ (id)alloc;
+- (void)dealloc;
+@end
+@interface NSObject (NSCoderMethods)
+- (id)awakeAfterUsingCoder:(NSCoder *)aDecoder;
+@end
+extern id NSAllocateObject(Class aClass, NSUInteger extraBytes, NSZone *zone);
+typedef struct {
+}
+NSFastEnumerationState;
+@protocol NSFastEnumeration - (NSUInteger)countByEnumeratingWithState:(NSFastEnumerationState *)state objects:(id *)stackbuf count:(NSUInteger)len;
+@end @class NSString, NSDictionary;
+@interface NSValue : NSObject <NSCopying, NSCoding> - (void)getValue:(void *)value;
+@end @interface NSNumber : NSValue - (char)charValue;
+- (id)initWithInt:(int)value;
+@end @class NSString;
+@interface NSArray : NSObject <NSCopying, NSMutableCopying, NSCoding, NSFastEnumeration> - (NSUInteger)count;
+@end @interface NSArray (NSArrayCreation) + (id)array;
+@end @interface NSAutoreleasePool : NSObject {
+}
+- (void)drain;
+@end extern NSString * const NSBundleDidLoadNotification;
+typedef double NSTimeInterval;
+@interface NSDate : NSObject <NSCopying, NSCoding> - (NSTimeInterval)timeIntervalSinceReferenceDate;
+@end typedef unsigned short unichar;
+@interface NSString : NSObject <NSCopying, NSMutableCopying, NSCoding> - (NSUInteger)length;
+- ( const char *)UTF8String;
+- (id)initWithUTF8String:(const char *)nullTerminatedCString;
++ (id)stringWithUTF8String:(const char *)nullTerminatedCString;
+@end @class NSString, NSURL, NSError;
+@interface NSData : NSObject <NSCopying, NSMutableCopying, NSCoding> - (NSUInteger)length;
++ (id)dataWithBytesNoCopy:(void *)bytes length:(NSUInteger)length;
++ (id)dataWithBytesNoCopy:(void *)bytes length:(NSUInteger)length freeWhenDone:(BOOL)b;
+@end @class NSLocale, NSDate, NSCalendar, NSTimeZone, NSError, NSArray, NSMutableDictionary;
+@interface NSDictionary : NSObject <NSCopying, NSMutableCopying, NSCoding, NSFastEnumeration> - (NSUInteger)count;
+@end @interface NSMutableDictionary : NSDictionary - (void)removeObjectForKey:(id)aKey;
+- (void)setObject:(id)anObject forKey:(id)aKey;
+@end @interface NSMutableDictionary (NSMutableDictionaryCreation) + (id)dictionaryWithCapacity:(NSUInteger)numItems;
+@end typedef double CGFloat;
+struct CGSize {
+};
+typedef struct CGSize CGSize;
+struct CGRect {
+};
+typedef struct CGRect CGRect;
+typedef mach_port_t io_object_t;
+typedef char io_name_t[128];
+typedef io_object_t io_iterator_t;
+typedef io_object_t io_service_t;
+typedef struct IONotificationPort * IONotificationPortRef;
+typedef void (*IOServiceMatchingCallback)( void * refcon, io_iterator_t iterator );
+io_service_t IOServiceGetMatchingService( mach_port_t masterPort, CFDictionaryRef matching );
+kern_return_t IOServiceGetMatchingServices( mach_port_t masterPort, CFDictionaryRef matching, io_iterator_t * existing );
+kern_return_t IOServiceAddNotification( mach_port_t masterPort, const io_name_t notificationType, CFDictionaryRef matching, mach_port_t wakePort, uintptr_t reference, io_iterator_t * notification ) __attribute__((deprecated));
+kern_return_t IOServiceAddMatchingNotification( IONotificationPortRef notifyPort, const io_name_t notificationType, CFDictionaryRef matching, IOServiceMatchingCallback callback, void * refCon, io_iterator_t * notification );
+CFMutableDictionaryRef IOServiceMatching( const char * name );
+CFMutableDictionaryRef IOServiceNameMatching( const char * name );
+CFMutableDictionaryRef IOBSDNameMatching( mach_port_t masterPort, uint32_t options, const char * bsdName );
+CFMutableDictionaryRef IOOpenFirmwarePathMatching( mach_port_t masterPort, uint32_t options, const char * path );
+CFMutableDictionaryRef IORegistryEntryIDMatching( uint64_t entryID );
+typedef struct __DASession * DASessionRef;
+extern DASessionRef DASessionCreate( CFAllocatorRef allocator );
+typedef struct __DADisk * DADiskRef;
+extern DADiskRef DADiskCreateFromBSDName( CFAllocatorRef allocator, DASessionRef session, const char * name );
+extern DADiskRef DADiskCreateFromIOMedia( CFAllocatorRef allocator, DASessionRef session, io_service_t media );
+extern CFDictionaryRef DADiskCopyDescription( DADiskRef disk );
+extern DADiskRef DADiskCopyWholeDisk( DADiskRef disk );
+@interface NSTask : NSObject - (id)init;
+@end typedef struct CGColorSpace *CGColorSpaceRef;
+typedef struct CGImage *CGImageRef;
+typedef struct CGLayer *CGLayerRef;
+@interface NSResponder : NSObject <NSCoding> {
+}
+@end @protocol NSAnimatablePropertyContainer - (id)animator;
+@end extern NSString *NSAnimationTriggerOrderIn ;
+@interface NSView : NSResponder <NSAnimatablePropertyContainer> {
+}
+@end @protocol NSValidatedUserInterfaceItem - (SEL)action;
+@end @protocol NSUserInterfaceValidations - (BOOL)validateUserInterfaceItem:(id <NSValidatedUserInterfaceItem>)anItem;
+@end @class NSDate, NSDictionary, NSError, NSException, NSNotification;
+@interface NSApplication : NSResponder <NSUserInterfaceValidations> {
+}
+@end enum {
+NSTerminateCancel = 0, NSTerminateNow = 1, NSTerminateLater = 2 };
+typedef NSUInteger NSApplicationTerminateReply;
+@protocol NSApplicationDelegate <NSObject> @optional - (NSApplicationTerminateReply)applicationShouldTerminate:(NSApplication *)sender;
+@end @class NSAttributedString, NSEvent, NSFont, NSFormatter, NSImage, NSMenu, NSText, NSView, NSTextView;
+@interface NSCell : NSObject <NSCopying, NSCoding> {
+}
+@end @class NSTextField, NSPanel, NSArray, NSWindow, NSImage, NSButton, NSError;
+typedef struct {
+}
+CVTimeStamp;
+@interface CIImage : NSObject <NSCoding, NSCopying> {
+}
+typedef int CIFormat;
+@end enum {
+kDAReturnSuccess = 0, kDAReturnError = (((0x3eU)&0x3f)<<26) | (((0x368)&0xfff)<<14) | 0x01, kDAReturnBusy = (((0x3eU)&0x3f)<<26) | (((0x368)&0xfff)<<14) | 0x02, kDAReturnBadArgument = (((0x3eU)&0x3f)<<26) | (((0x368)&0xfff)<<14) | 0x03, kDAReturnExclusiveAccess = (((0x3eU)&0x3f)<<26) | (((0x368)&0xfff)<<14) | 0x04, kDAReturnNoResources = (((0x3eU)&0x3f)<<26) | (((0x368)&0xfff)<<14) | 0x05, kDAReturnNotFound = (((0x3eU)&0x3f)<<26) | (((0x368)&0xfff)<<14) | 0x06, kDAReturnNotMounted = (((0x3eU)&0x3f)<<26) | (((0x368)&0xfff)<<14) | 0x07, kDAReturnNotPermitted = (((0x3eU)&0x3f)<<26) | (((0x368)&0xfff)<<14) | 0x08, kDAReturnNotPrivileged = (((0x3eU)&0x3f)<<26) | (((0x368)&0xfff)<<14) | 0x09, kDAReturnNotReady = (((0x3eU)&0x3f)<<26) | (((0x368)&0xfff)<<14) | 0x0A, kDAReturnNotWritable = (((0x3eU)&0x3f)<<26) | (((0x368)&0xfff)<<14) | 0x0B, kDAReturnUnsupported = (((0x3eU)&0x3f)<<26) | (((0x368)&0xfff)<<14) | 0x0C };
+typedef mach_error_t DAReturn;
+typedef const struct __DADissenter * DADissenterRef;
+extern DADissenterRef DADissenterCreate( CFAllocatorRef allocator, DAReturn status, CFStringRef string );
+@interface CIContext: NSObject {
+}
+- (CGImageRef)createCGImage:(CIImage *)im fromRect:(CGRect)r;
+- (CGImageRef)createCGImage:(CIImage *)im fromRect:(CGRect)r format:(CIFormat)f colorSpace:(CGColorSpaceRef)cs;
+- (CGLayerRef)createCGLayerWithSize:(CGSize)size info:(CFDictionaryRef)d;
+@end extern NSString* const QCRendererEventKey;
+@protocol QCCompositionRenderer - (NSDictionary*) attributes;
+@end @interface QCRenderer : NSObject <QCCompositionRenderer> {
+}
+- (id) createSnapshotImageOfType:(NSString*)type;
+@end extern NSString* const QCViewDidStartRenderingNotification;
+@interface QCView : NSView <QCCompositionRenderer> {
+}
+- (id) createSnapshotImageOfType:(NSString*)type;
+@end enum {
+ICEXIFOrientation1 = 1, ICEXIFOrientation2 = 2, ICEXIFOrientation3 = 3, ICEXIFOrientation4 = 4, ICEXIFOrientation5 = 5, ICEXIFOrientation6 = 6, ICEXIFOrientation7 = 7, ICEXIFOrientation8 = 8, };
+@class ICDevice;
+@protocol ICDeviceDelegate <NSObject> @required - (void)didRemoveDevice:(ICDevice*)device;
+@end extern NSString *const ICScannerStatusWarmingUp;
+@class ICScannerDevice;
+@protocol ICScannerDeviceDelegate <ICDeviceDelegate> @optional - (void)scannerDeviceDidBecomeAvailable:(ICScannerDevice*)scanner;
+@end
+
+typedef long unsigned int __darwin_size_t;
+typedef __darwin_size_t size_t;
+typedef unsigned long CFTypeID;
+struct CGPoint {
+ CGFloat x;
+ CGFloat y;
+};
+typedef struct CGPoint CGPoint;
+typedef struct CGGradient *CGGradientRef;
+typedef uint32_t CGGradientDrawingOptions;
+extern CFTypeID CGGradientGetTypeID(void);
+extern CGGradientRef CGGradientCreateWithColorComponents(CGColorSpaceRef
+ space, const CGFloat components[], const CGFloat locations[], size_t count);
+extern CGGradientRef CGGradientCreateWithColors(CGColorSpaceRef space,
+ CFArrayRef colors, const CGFloat locations[]);
+extern CGGradientRef CGGradientRetain(CGGradientRef gradient);
+extern void CGGradientRelease(CGGradientRef gradient);
+typedef struct CGContext *CGContextRef;
+extern void CGContextDrawLinearGradient(CGContextRef context,
+ CGGradientRef gradient, CGPoint startPoint, CGPoint endPoint,
+ CGGradientDrawingOptions options);
+extern CGColorSpaceRef CGColorSpaceCreateDeviceRGB(void);
+
+//===----------------------------------------------------------------------===//
+// Test cases.
+//===----------------------------------------------------------------------===//
+
+class SmartPointer {
+ id x;
+public:
+ SmartPointer(id x) : x(x) {}
+ ~SmartPointer() { [x release]; }
+
+ void adopt(id x);
+ void noAdopt(id x);
+};
+
+void test_positive() {
+ id x = [[NSObject alloc] init]; // expected-warning {{leak}}
+}
+
+void test_smartpointer_1() {
+ id x = [[NSObject alloc] init]; // no-warning
+ SmartPointer foo(x);
+}
+
+void test_smartpointer_2() {
+ id x = [[NSObject alloc] init]; // no-warning
+ SmartPointer foo(0);
+ foo.adopt(x);
+}
+
+// FIXME: Eventually we want annotations to say whether or not
+// a C++ method claims ownership of an Objective-C object.
+void test_smartpointer_3() {
+ id x = [[NSObject alloc] init]; // no-warning
+ SmartPointer foo(0);
+ foo.noAdopt(x);
+}
+
+
diff --git a/test/Analysis/string.c b/test/Analysis/string.c
index 19c838c..e6baf51 100644
--- a/test/Analysis/string.c
+++ b/test/Analysis/string.c
@@ -328,74 +328,6 @@ void strcpy_no_overflow(char *y) {
}
//===----------------------------------------------------------------------===
-// strncpy()
-//===----------------------------------------------------------------------===
-
-#ifdef VARIANT
-
-#define __strncpy_chk BUILTIN(__strncpy_chk)
-char *__strncpy_chk(char *restrict s1, const char *restrict s2, size_t n, size_t destlen);
-
-#define strncpy(a,b,c) __strncpy_chk(a,b,c, (size_t)-1)
-
-#else /* VARIANT */
-
-#define strncpy BUILTIN(strncpy)
-char *strncpy(char *restrict s1, const char *restrict s2, size_t n);
-
-#endif /* VARIANT */
-
-
-void strncpy_null_dst(char *x) {
- strncpy(NULL, x, 1); // expected-warning{{Null pointer argument in call to byte string function}}
-}
-
-void strncpy_null_src(char *x) {
- strncpy(x, NULL, 1); // expected-warning{{Null pointer argument in call to byte string function}}
-}
-
-void strncpy_fn(char *x) {
- strncpy(x, (char*)&strncpy_fn, 1); // expected-warning{{Argument to byte string function is the address of the function 'strncpy_fn', which is not a null-terminated string}}
-}
-
-void strncpy_effects(char *x, char *y) {
- char a = x[0];
-
- if (strncpy(x, y, strlen(y)) != x)
- (void)*(char*)0; // no-warning
-
- if (strlen(x) != strlen(y))
- (void)*(char*)0; // no-warning
-
- if (a != x[0])
- (void)*(char*)0; // expected-warning{{null}}
-}
-
-void strncpy_overflow(char *y) {
- char x[4];
- if (strlen(y) == 4)
- strncpy(x, y, strlen(y)); // expected-warning{{Byte string function overflows destination buffer}}
-}
-
-void strncpy_len_overflow(char *y) {
- char x[4];
- if (strlen(y) == 3)
- strncpy(x, y, sizeof(x)); // no-warning
-}
-
-void strncpy_no_overflow(char *y) {
- char x[4];
- if (strlen(y) == 3)
- strncpy(x, y, strlen(y)); // no-warning
-}
-
-void strncpy_no_len_overflow(char *y) {
- char x[4];
- if (strlen(y) == 4)
- strncpy(x, y, sizeof(x)-1); // no-warning
-}
-
-//===----------------------------------------------------------------------===
// stpcpy()
//===----------------------------------------------------------------------===
@@ -872,3 +804,109 @@ void strcasecmp_diff_length_3() {
if (strcasecmp(x, y) != -1)
(void)*(char*)0; // no-warning
}
+
+//===----------------------------------------------------------------------===
+// strncasecmp()
+//===----------------------------------------------------------------------===
+
+#define strncasecmp BUILTIN(strncasecmp)
+int strncasecmp(const char *restrict s1, const char *restrict s2, size_t n);
+
+void strncasecmp_constant0() {
+ if (strncasecmp("abc", "Abc", 3) != 0)
+ (void)*(char*)0; // no-warning
+}
+
+void strncasecmp_constant_and_var_0() {
+ char *x = "abc";
+ if (strncasecmp(x, "Abc", 3) != 0)
+ (void)*(char*)0; // no-warning
+}
+
+void strncasecmp_constant_and_var_1() {
+ char *x = "abc";
+ if (strncasecmp("Abc", x, 3) != 0)
+ (void)*(char*)0; // no-warning
+}
+
+void strncasecmp_0() {
+ char *x = "abc";
+ char *y = "Abc";
+ if (strncasecmp(x, y, 3) != 0)
+ (void)*(char*)0; // no-warning
+}
+
+void strncasecmp_1() {
+ char *x = "Bcd";
+ char *y = "abc";
+ if (strncasecmp(x, y, 3) != 1)
+ (void)*(char*)0; // no-warning
+}
+
+void strncasecmp_2() {
+ char *x = "abc";
+ char *y = "Bcd";
+ if (strncasecmp(x, y, 3) != -1)
+ (void)*(char*)0; // no-warning
+}
+
+void strncasecmp_null_0() {
+ char *x = NULL;
+ char *y = "123";
+ strncasecmp(x, y, 3); // expected-warning{{Null pointer argument in call to byte string function}}
+}
+
+void strncasecmp_null_1() {
+ char *x = "123";
+ char *y = NULL;
+ strncasecmp(x, y, 3); // expected-warning{{Null pointer argument in call to byte string function}}
+}
+
+void strncasecmp_diff_length_0() {
+ char *x = "abcde";
+ char *y = "aBd";
+ if (strncasecmp(x, y, 5) != -1)
+ (void)*(char*)0; // no-warning
+}
+
+void strncasecmp_diff_length_1() {
+ char *x = "abc";
+ char *y = "aBdef";
+ if (strncasecmp(x, y, 5) != -1)
+ (void)*(char*)0; // no-warning
+}
+
+void strncasecmp_diff_length_2() {
+ char *x = "aBcDe";
+ char *y = "abc";
+ if (strncasecmp(x, y, 5) != 1)
+ (void)*(char*)0; // no-warning
+}
+
+void strncasecmp_diff_length_3() {
+ char *x = "aBc";
+ char *y = "abcde";
+ if (strncasecmp(x, y, 5) != -1)
+ (void)*(char*)0; // no-warning
+}
+
+void strncasecmp_diff_length_4() {
+ char *x = "abcde";
+ char *y = "aBc";
+ if (strncasecmp(x, y, 3) != 0)
+ (void)*(char*)0; // no-warning
+}
+
+void strncasecmp_diff_length_5() {
+ char *x = "abcde";
+ char *y = "aBd";
+ if (strncasecmp(x, y, 3) != -1)
+ (void)*(char*)0; // no-warning
+}
+
+void strncasecmp_diff_length_6() {
+ char *x = "aBDe";
+ char *y = "abc";
+ if (strncasecmp(x, y, 3) != 1)
+ (void)*(char*)0; // no-warning
+}
diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt
index 544ed3d..e35413a 100644
--- a/test/CMakeLists.txt
+++ b/test/CMakeLists.txt
@@ -75,19 +75,6 @@ if(PYTHONINTERP_FOUND)
add_custom_target(clang-test.deps)
set_target_properties(clang-test.deps PROPERTIES FOLDER "Clang tests")
- foreach(testdir ${CLANG_TEST_DIRECTORIES})
- add_custom_target(clang-test-${testdir}
- COMMAND ${PYTHON_EXECUTABLE}
- ${LIT}
- --param clang_site_config=${CMAKE_CURRENT_BINARY_DIR}/lit.site.cfg
- --param build_config=${CMAKE_CFG_INTDIR}
- ${LIT_ARGS}
- ${CMAKE_CURRENT_BINARY_DIR}/${testdir}
- DEPENDS clang c-index-test FileCheck not count
- COMMENT "Running Clang regression tests in ${testdir}")
- set_target_properties(clang-test-${testdir} PROPERTIES FOLDER "Clang tests")
- endforeach()
-
add_custom_target(clang-test
COMMAND ${PYTHON_EXECUTABLE}
${LIT}
@@ -100,17 +87,6 @@ if(PYTHONINTERP_FOUND)
COMMENT "Running Clang regression tests")
set_target_properties(clang-test PROPERTIES FOLDER "Clang tests")
- add_custom_target(clang-c++tests
- COMMAND ${PYTHON_EXECUTABLE}
- ${LIT}
- --param clang_site_config=${CMAKE_CURRENT_BINARY_DIR}/lit.site.cfg
- --param build_config=${CMAKE_CFG_INTDIR}
- ${LIT_ARGS}
- ${CMAKE_CURRENT_SOURCE_DIR}/../utils/C++Tests
- DEPENDS clang c-index-test FileCheck not count
- COMMENT "Running Clang regression tests")
- set_target_properties(clang-c++tests PROPERTIES FOLDER "Clang tests")
-
if( NOT CLANG_BUILT_STANDALONE )
add_custom_target(check-all
COMMAND ${PYTHON_EXECUTABLE}
diff --git a/test/CXX/basic/basic.lookup/basic.lookup.argdep/p4.cpp b/test/CXX/basic/basic.lookup/basic.lookup.argdep/p4.cpp
index 1e5a823..ccadf41 100644
--- a/test/CXX/basic/basic.lookup/basic.lookup.argdep/p4.cpp
+++ b/test/CXX/basic/basic.lookup/basic.lookup.argdep/p4.cpp
@@ -45,6 +45,9 @@ namespace Test {
namespace test1 {
template <class T> class A {
template <class U> friend void foo(A &, U); // expected-note {{not viable: 1st argument ('const A<int>') would lose const qualifier}}
+
+ public:
+ A();
};
void test() {
diff --git a/test/CXX/class.access/class.friend/p2-cxx03.cpp b/test/CXX/class.access/class.friend/p2-cxx03.cpp
index 0391c4b..82cddc2 100644
--- a/test/CXX/class.access/class.friend/p2-cxx03.cpp
+++ b/test/CXX/class.access/class.friend/p2-cxx03.cpp
@@ -1,7 +1,7 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s
template<typename T>
class X0 {
- friend T; // expected-warning{{non-class type 'T' cannot be a friend}}
+ friend T; // expected-warning{{non-class friend type 'T' is a C++0x extension}}
};
class X1 { };
diff --git a/test/CXX/class.access/p4.cpp b/test/CXX/class.access/p4.cpp
index 4228a44..add3635 100644
--- a/test/CXX/class.access/p4.cpp
+++ b/test/CXX/class.access/p4.cpp
@@ -96,7 +96,7 @@ namespace test2 {
A a; // expected-error {{calling a private constructor}}
A A::foo; // okay
- class B : A { }; // expected-error {{base class 'test2::A' has private constructor}}
+ class B : A { }; // expected-error {{base class 'test2::A' has private default constructor}}
B b; // expected-note{{implicit default constructor}}
class C : virtual A {
@@ -104,7 +104,7 @@ namespace test2 {
C();
};
- class D : C { }; // expected-error {{inherited virtual base class 'test2::A' has private constructor}}
+ class D : C { }; // expected-error {{inherited virtual base class 'test2::A' has private default constructor}}
D d; // expected-note{{implicit default constructor}}
}
@@ -206,7 +206,7 @@ namespace test5 {
class Test1 { A a; }; // expected-error {{private member}}
void test1() {
- Test1 a;
+ Test1 a;
a = Test1(); // expected-note{{implicit default copy}}
}
diff --git a/test/CXX/class/class.friend/p2.cpp b/test/CXX/class/class.friend/p2.cpp
index eb5036f..87b69c0 100644
--- a/test/CXX/class/class.friend/p2.cpp
+++ b/test/CXX/class/class.friend/p2.cpp
@@ -4,7 +4,7 @@ struct B0;
class A {
friend class B {}; // expected-error {{cannot define a type in a friend declaration}}
- friend int; // expected-warning {{non-class type 'int' cannot be a friend}}
- friend B0; // expected-warning {{must specify 'struct' to befriend}}
+ friend int; // expected-warning {{non-class friend type 'int' is a C++0x extension}}
+ friend B0; // expected-warning {{specify 'struct' to befriend 'B0'}}
friend class C; // okay
};
diff --git a/test/CXX/class/class.mem/p1b.cpp b/test/CXX/class/class.mem/p1b.cpp
index d3493f6..3e8c985 100644
--- a/test/CXX/class/class.mem/p1b.cpp
+++ b/test/CXX/class/class.mem/p1b.cpp
@@ -16,7 +16,7 @@ public:
void a3(int a = 42);
- // CHEKC: error: use of undeclared identifier 'first'
+ // CHECK: error: use of undeclared identifier 'first'
void a4(int a = first); // expected-error{{use of undeclared identifier 'first'}}
class B {
diff --git a/test/CXX/class/class.mem/p5-0x.cpp b/test/CXX/class/class.mem/p5-0x.cpp
new file mode 100644
index 0000000..78560e2
--- /dev/null
+++ b/test/CXX/class/class.mem/p5-0x.cpp
@@ -0,0 +1,9 @@
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++0x %s
+
+int f();
+
+struct S
+{
+ int a = f(); // ok
+ int b = g(); // expected-error {{use of undeclared identifier 'g'}}
+};
diff --git a/test/CXX/dcl.dcl/basic.namespace/namespace.def/p7.cpp b/test/CXX/dcl.dcl/basic.namespace/namespace.def/p7.cpp
index 198b013..e3d3d68 100644
--- a/test/CXX/dcl.dcl/basic.namespace/namespace.def/p7.cpp
+++ b/test/CXX/dcl.dcl/basic.namespace/namespace.def/p7.cpp
@@ -3,7 +3,7 @@
namespace NIL {} // expected-note {{previous definition}}
inline namespace NIL {} // expected-error {{cannot be reopened as inline}}
inline namespace IL {} // expected-note {{previous definition}}
-namespace IL {} // expected-error {{cannot be reopened as non-inline}}
+namespace IL {} // expected-warning{{inline namespace cannot be re-opened as a non-inline namespace}}
namespace {} // expected-note {{previous definition}}
inline namespace {} // expected-error {{cannot be reopened as inline}}
diff --git a/test/CXX/dcl.dcl/dcl.spec/dcl.stc/p1.cpp b/test/CXX/dcl.dcl/dcl.spec/dcl.stc/p1.cpp
new file mode 100644
index 0000000..40917b8
--- /dev/null
+++ b/test/CXX/dcl.dcl/dcl.spec/dcl.stc/p1.cpp
@@ -0,0 +1,32 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s
+
+// A storage-class-specifier shall not be specified in an explicit
+// specialization (14.7.3) or an explicit instantiation (14.7.2)
+// directive.
+template<typename T> void f(T) {}
+template<typename T> static void g(T) {}
+
+
+template<> static void f<int>(int); // expected-error{{explicit specialization cannot have a storage class}}
+template static void f<float>(float); // expected-error{{explicit instantiation cannot have a storage class}}
+
+template<> void f<double>(double);
+template void f<long>(long);
+
+template<> static void g<int>(int); // expected-error{{explicit specialization cannot have a storage class}}
+template static void g<float>(float); // expected-error{{explicit instantiation cannot have a storage class}}
+
+template<> void g<double>(double);
+template void g<long>(long);
+
+template<typename T>
+struct X {
+ static int value;
+};
+
+template<typename T>
+int X<T>::value = 17;
+
+template static int X<int>::value; // expected-error{{explicit instantiation cannot have a storage class}}
+
+template<> static int X<float>::value; // expected-error{{'static' can only be specified inside the class definition}}
diff --git a/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p4.cpp b/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p4.cpp
index 34a1784..8a68e4b 100644
--- a/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p4.cpp
+++ b/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p4.cpp
@@ -22,14 +22,21 @@ void f() {
new const auto (0);
new (auto) (0.0);
-#if 0
- // When clang supports for-range:
- for (auto i : {1,2,3}) {
+ int arr[] = {1, 2, 3};
+ for (auto i : arr) {
}
-
- // When clang supports inline initialization of members.
- class X {
- static const auto &n = 'x';
- };
-#endif
}
+
+class X {
+ static const auto n = 'x';
+
+ auto m = 0; // expected-error {{'auto' not allowed in non-static class member}}
+};
+
+struct S {
+ static const auto a; // expected-error {{declaration of variable 'a' with type 'auto const' requires an initializer}}
+ static const auto b = 0;
+ static const int c;
+};
+const int S::b;
+const auto S::c = 0;
diff --git a/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p5.cpp b/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p5.cpp
index 09245cf..fabfb53 100644
--- a/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p5.cpp
+++ b/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p5.cpp
@@ -3,13 +3,13 @@
struct S {
virtual ~S();
- auto a; // expected-error{{'auto' not allowed in struct member}}
- auto *b; // expected-error{{'auto' not allowed in struct member}}
- const auto c; // expected-error{{'auto' not allowed in struct member}}
+ auto a; // expected-error{{'auto' not allowed in non-static struct member}}
+ auto *b; // expected-error{{'auto' not allowed in non-static struct member}}
+ const auto c; // expected-error{{'auto' not allowed in non-static struct member}}
void f() throw (auto); // expected-error{{'auto' not allowed here}}
- friend auto; // expected-error{{'auto' not allowed in struct member}}
+ friend auto; // expected-error{{'auto' not allowed in non-static struct member}}
operator auto(); // expected-error{{'auto' not allowed here}}
};
diff --git a/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.type.elab/p2-0x.cpp b/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.type.elab/p2-0x.cpp
new file mode 100644
index 0000000..81204d8
--- /dev/null
+++ b/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.type.elab/p2-0x.cpp
@@ -0,0 +1,19 @@
+// RUN: %clang_cc1 -std=c++0x -fsyntax-only -verify %s
+
+struct A { typedef int type; };
+template<typename T> using X = A; // expected-note {{declared here}}
+struct X<int>* p2; // expected-error {{elaborated type refers to a type alias template}}
+
+
+template<typename T> using Id = T; // expected-note {{declared here}}
+template<template<typename> class F>
+struct Y {
+ struct F<int> i; // expected-error {{elaborated type refers to a type alias template}}
+ typename F<A>::type j; // ok
+
+ // FIXME: don't produce the diagnostic both for the definition and the instantiation.
+ template<typename T> using U = F<char>; // expected-note 2{{declared here}}
+ struct Y<F>::template U<char> k; // expected-error 2{{elaborated type refers to a type alias template}}
+ typename Y<F>::template U<char> l; // ok
+};
+template struct Y<Id>; // expected-note {{requested here}}
diff --git a/test/CXX/dcl.dcl/dcl.spec/dcl.type/p3-0x.cpp b/test/CXX/dcl.dcl/dcl.spec/dcl.type/p3-0x.cpp
index 10184a0..b93e8e3 100644
--- a/test/CXX/dcl.dcl/dcl.spec/dcl.type/p3-0x.cpp
+++ b/test/CXX/dcl.dcl/dcl.spec/dcl.type/p3-0x.cpp
@@ -1,15 +1,14 @@
// RUN: %clang_cc1 -std=c++0x -fsyntax-only -verify %s
-// FIXME: when clang supports alias-declarations.
-#if 0
using X = struct { // ok
};
-#endif
+template<typename T> using Y = struct { // expected-error {{can not be defined in a type alias template}}
+};
class K {
virtual ~K();
- // FIXME: the diagnostic here isn't very good
- operator struct S {} (); // expected-error 2{{}}
+ // FIXME: the diagnostic here is really bad
+ operator struct S {} (); // expected-error 2{{}} expected-note {{}}
};
void f() {
diff --git a/test/CXX/dcl.decl/dcl.init/dcl.init.aggr/p1-0x.cpp b/test/CXX/dcl.decl/dcl.init/dcl.init.aggr/p1-0x.cpp
new file mode 100644
index 0000000..9b92340
--- /dev/null
+++ b/test/CXX/dcl.decl/dcl.init/dcl.init.aggr/p1-0x.cpp
@@ -0,0 +1,63 @@
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++0x %s
+
+// An aggregate is an array or a class...
+struct Aggr {
+private:
+ static const int n;
+ void f();
+protected:
+ struct Inner { int m; };
+public:
+ bool &br;
+};
+bool b;
+Aggr ag = { b };
+
+// with no user-provided constructors, ...
+struct NonAggr1a {
+ NonAggr1a(int, int);
+ int k;
+};
+// In C++03, this is {{non-aggregate type 'NonAggr1a'}}.
+// In C++0x, 'user-provided' is only defined for special member functions, so
+// this type is considered to be an aggregate. This is probably a langauge
+// defect.
+NonAggr1a na1a = { 42 };
+
+struct NonAggr1b {
+ NonAggr1b(const NonAggr1b &);
+ int k;
+};
+NonAggr1b na1b = { 42 }; // expected-error {{non-aggregate type 'NonAggr1b'}}
+
+// no brace-or-equal-initializers for non-static data members, ...
+struct NonAggr2 {
+ int m = { 123 };
+};
+NonAggr2 na2 = { 42 }; // expected-error {{non-aggregate type 'NonAggr2'}}
+
+// no private...
+struct NonAggr3 {
+private:
+ int n;
+};
+NonAggr3 na3 = { 42 }; // expected-error {{non-aggregate type 'NonAggr3'}}
+
+// or protected non-static data members, ...
+struct NonAggr4 {
+protected:
+ int n;
+};
+NonAggr4 na4 = { 42 }; // expected-error {{non-aggregate type 'NonAggr4'}}
+
+// no base classes, ...
+struct NonAggr5 : Aggr {
+};
+NonAggr5 na5 = { b }; // expected-error {{non-aggregate type 'NonAggr5'}}
+
+// and no virtual functions.
+struct NonAggr6 {
+ virtual void f();
+ int n;
+};
+NonAggr6 na6 = { 42 }; // expected-error {{non-aggregate type 'NonAggr6'}}
diff --git a/test/CXX/dcl.decl/dcl.init/p14-0x.cpp b/test/CXX/dcl.decl/dcl.init/p14-0x.cpp
new file mode 100644
index 0000000..e5b5889
--- /dev/null
+++ b/test/CXX/dcl.decl/dcl.init/p14-0x.cpp
@@ -0,0 +1,44 @@
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++0x %s
+
+struct NoDefault {
+ NoDefault() = delete; // expected-note {{here}}
+ NoDefault(int);
+};
+struct Explicit { // expected-note {{candidate}} expected-note {{here}}
+ explicit Explicit(int);
+};
+struct NoCopy {
+ NoCopy();
+ NoCopy(const NoCopy &) = delete; // expected-note {{here}}
+};
+struct NoMove {
+ NoMove();
+ NoMove(NoMove &&) = delete; // expected-note {{here}}
+};
+class Private {
+ Private(int); // expected-note {{here}}
+public:
+ Private();
+};
+class Friend {
+ friend class S;
+ Friend(int);
+};
+
+
+class S {
+ NoDefault nd1;
+ NoDefault nd2 = 42;
+ Explicit e1; // expected-note {{here}}
+ Explicit e2 = 42; // expected-error {{no viable conversion}}
+ NoCopy nc = NoCopy(); // expected-error {{call to deleted}}
+ NoMove nm = NoMove(); // expected-error {{call to deleted}}
+ Private p = 42; // expected-error {{private constructor}}
+ Friend f = 42;
+
+ S() {} // expected-error {{call to deleted constructor of 'NoDefault'}} \
+ expected-error {{must explicitly initialize the member 'e1' which does not have a default constructor}}
+ S(int) : nd1(42), e1(42) {}
+};
+
+// FIXME: test the other forms which use copy-initialization
diff --git a/test/CXX/dcl.decl/dcl.init/p6.cpp b/test/CXX/dcl.decl/dcl.init/p6.cpp
index da6f5b5..514fd0c 100644
--- a/test/CXX/dcl.decl/dcl.init/p6.cpp
+++ b/test/CXX/dcl.decl/dcl.init/p6.cpp
@@ -14,3 +14,15 @@ void test_const_default_init() {
const HasUserDefault x2;
const int x3; // expected-error{{default initialization of an object of const type 'const int'}}
}
+
+// rdar://8501008
+struct s0 {};
+struct s1 { static const s0 foo; };
+const struct s0 s1::foo; // expected-error{{default initialization of an object of const type 'const struct s0' requires a user-provided default constructor}}
+
+template<typename T>
+struct s2 {
+ static const s0 foo;
+};
+
+template<> const struct s0 s2<int>::foo; // okay
diff --git a/test/CXX/except/except.spec/p1.cpp b/test/CXX/except/except.spec/p1.cpp
index 0559285..86924bb 100644
--- a/test/CXX/except/except.spec/p1.cpp
+++ b/test/CXX/except/except.spec/p1.cpp
@@ -58,3 +58,16 @@ namespace noex {
void g2(bool b) noexcept(b); // expected-error {{argument to noexcept specifier must be a constant expression}}
}
+
+namespace noexcept_unevaluated {
+ template<typename T> void f(T) {
+ T* x = 1;
+ }
+
+ template<typename T>
+ void g(T x) noexcept((f(x), sizeof(T) == 4)) { }
+
+ void h() {
+ g(1);
+ }
+}
diff --git a/test/CXX/except/except.spec/p14.cpp b/test/CXX/except/except.spec/p14.cpp
index f5e83ea..f42fbe9 100644
--- a/test/CXX/except/except.spec/p14.cpp
+++ b/test/CXX/except/except.spec/p14.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fcxx-exceptions -fexceptions -verify %s
+// RUN: %clang_cc1 -fcxx-exceptions -fexceptions -verify -std=c++0x %s
struct A { };
struct B { };
struct C { };
@@ -27,3 +27,15 @@ void test_CA() {
CA2 &(CA2::*captr3)(const CA2&) throw(A) = &CA2::operator=; // expected-error{{target exception specification is not superset of source}}
CA2 &(CA2::*captr4)(const CA2&) throw(B) = &CA2::operator=; // expected-error{{target exception specification is not superset of source}}
}
+
+// In-class member initializers.
+struct IC0 {
+ int inClassInit = 0;
+};
+struct IC1 {
+ int inClassInit = (throw B(), 0);
+};
+// FIXME: the exception specification on the default constructor is wrong:
+// we cannot currently compute the set of thrown types.
+static_assert(noexcept(IC0()), "IC0() does not throw");
+static_assert(!noexcept(IC1()), "IC1() throws");
diff --git a/test/CXX/except/except.spec/p9-dynamic.cpp b/test/CXX/except/except.spec/p9-dynamic.cpp
index 490d2fa..3f496f2 100644
--- a/test/CXX/except/except.spec/p9-dynamic.cpp
+++ b/test/CXX/except/except.spec/p9-dynamic.cpp
@@ -7,5 +7,5 @@ void target() throw(int)
// CHECK: invoke void @_Z8externalv()
external();
}
-// CHECK: call i32 (i8*, i8*, ...)* @llvm.eh.selector({{.*}} i8* bitcast (i8** @_ZTIi to i8*), i8* null) nounwind
+// CHECK: call i32 (i8*, i8*, ...)* @llvm.eh.selector({{.*}} i8* bitcast (i8** @_ZTIi to i8*)) nounwind
// CHECK: call void @__cxa_call_unexpected
diff --git a/test/CXX/expr/expr.const/p2-0x.cpp b/test/CXX/expr/expr.const/p2-0x.cpp
new file mode 100644
index 0000000..1b38cf1
--- /dev/null
+++ b/test/CXX/expr/expr.const/p2-0x.cpp
@@ -0,0 +1,25 @@
+// RUN: %clang_cc1 -fsyntax-only -std=c++0x -verify %s
+
+// PR9999
+template<bool v>
+class bitWidthHolding {
+public:
+ static const
+ unsigned int width = (v == 0 ? 0 : bitWidthHolding<(v >> 1)>::width + 1);
+};
+
+static const int width=bitWidthHolding<255>::width;
+
+template<bool b>
+struct always_false {
+ static const bool value = false;
+};
+
+template<bool b>
+struct and_or {
+ static const bool and_value = b && and_or<always_false<b>::value>::and_value;
+ static const bool or_value = !b || and_or<always_false<b>::value>::or_value;
+};
+
+static const bool and_value = and_or<true>::and_value;
+static const bool or_value = and_or<true>::or_value;
diff --git a/test/CXX/expr/expr.post/expr.call/p7-0x.cpp b/test/CXX/expr/expr.post/expr.call/p7-0x.cpp
new file mode 100644
index 0000000..bb4726d
--- /dev/null
+++ b/test/CXX/expr/expr.post/expr.call/p7-0x.cpp
@@ -0,0 +1,17 @@
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++0x %s
+
+struct X1 {
+ X1();
+};
+
+struct X2 {
+ X2();
+ ~X2();
+};
+
+void vararg(...);
+
+void f(X1 x1, X2 x2) {
+ vararg(x1); // okay
+ vararg(x2); // expected-error{{cannot pass object of non-trivial type 'X2' through variadic function; call will abort at runtime}}
+}
diff --git a/test/CXX/expr/expr.prim/p12-0x.cpp b/test/CXX/expr/expr.prim/p12-0x.cpp
new file mode 100644
index 0000000..0ff29a1
--- /dev/null
+++ b/test/CXX/expr/expr.prim/p12-0x.cpp
@@ -0,0 +1,12 @@
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++0x %s
+
+struct S {
+ int *j = &nonexistent; // expected-error {{use of undeclared identifier 'nonexistent'}}
+ int *m = &n; // ok
+
+ int n = f(); // ok
+ int f();
+};
+
+int i = sizeof(S::m); // ok
+int j = sizeof(S::m + 42); // ok
diff --git a/test/CXX/expr/expr.prim/p4-0x.cpp b/test/CXX/expr/expr.prim/p4-0x.cpp
new file mode 100644
index 0000000..13735fa
--- /dev/null
+++ b/test/CXX/expr/expr.prim/p4-0x.cpp
@@ -0,0 +1,10 @@
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++0x %s
+
+struct S {
+ S *p = this; // ok
+ decltype(this) q; // expected-error {{invalid use of 'this' outside of a nonstatic member function}} \
+ expected-error {{C++ requires a type specifier for all declarations}}
+
+ int arr[sizeof(this)]; // expected-error {{invalid use of 'this' outside of a nonstatic member function}}
+ int sz = sizeof(this); // ok
+};
diff --git a/test/CXX/expr/expr.unary/expr.unary.noexcept/sema.cpp b/test/CXX/expr/expr.unary/expr.unary.noexcept/sema.cpp
index 28ed62c..6d1e523 100644
--- a/test/CXX/expr/expr.unary/expr.unary.noexcept/sema.cpp
+++ b/test/CXX/expr/expr.unary/expr.unary.noexcept/sema.cpp
@@ -97,6 +97,8 @@ struct Bad2 {
void operator delete(void*) throw(int);
};
+typedef int X;
+
void implicits() {
N(new int);
P(new (0) int);
@@ -113,6 +115,7 @@ void implicits() {
N(static_cast<int>(s));
P(static_cast<float>(s));
N(Bad1());
+ P(X().~X());
}
struct V {
@@ -155,12 +158,16 @@ void gencon() {
N(G3());
}
+template <class T> void f(T&&) noexcept;
template <typename T, bool b>
void late() {
B(b, typeid(*(T*)0));
B(b, T(1));
B(b, static_cast<T>(S2(0, 0)));
B(b, S1() + T());
+ P(f(T()));
+ P(new (0) T);
+ P(delete (T*)0);
}
struct S3 {
virtual ~S3() throw();
@@ -168,9 +175,15 @@ struct S3 {
explicit S3(int);
S3(const S2&);
};
+template <class T> T&& f2() noexcept;
+template <typename T>
+void late2() {
+ P(dynamic_cast<S3&>(f2<T&>()));
+}
void operator +(const S1&, float) throw();
void operator +(const S1&, const S3&);
void tlate() {
late<float, true>();
late<S3, false>();
+ late2<S3>();
}
diff --git a/test/CXX/special/class.ctor/p5-0x.cpp b/test/CXX/special/class.ctor/p5-0x.cpp
new file mode 100644
index 0000000..2123d16
--- /dev/null
+++ b/test/CXX/special/class.ctor/p5-0x.cpp
@@ -0,0 +1,173 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s -std=c++0x
+
+struct DefaultedDefCtor1 {};
+struct DefaultedDefCtor2 { DefaultedDefCtor2() = default; };
+struct DeletedDefCtor { DeletedDefCtor() = delete; DeletedDefCtor(int); };
+class PrivateDefCtor { PrivateDefCtor() = default; public: PrivateDefCtor(int); };
+struct DeletedDtor { ~DeletedDtor() = delete; };
+class PrivateDtor { ~PrivateDtor() = default; };
+class Friend {
+ Friend() = default; ~Friend() = default;
+ friend struct NotDeleted6c;
+ friend struct NotDeleted7i;
+ friend struct NotDeleted7j;
+ friend struct NotDeleted7k;
+};
+struct UserProvidedDefCtor { UserProvidedDefCtor() {} };
+int n;
+
+
+// A defaulted default constructor for a class X is defined as deleted if:
+
+// - X is a union-like class that has a variant member with a non-trivial
+// default constructor,
+union Deleted1a { UserProvidedDefCtor u; }; // expected-note {{deleted here}}
+Deleted1a d1a; // expected-error {{deleted constructor}}
+// FIXME: treating this as having a deleted default constructor is probably a
+// bug in the standard.
+union Deleted1b { UserProvidedDefCtor u = UserProvidedDefCtor(); }; // expected-note {{deleted here}}
+Deleted1b d1b; // expected-error {{deleted constructor}}
+union NotDeleted1a { DefaultedDefCtor1 nu; };
+NotDeleted1a nd1a;
+// FIXME: clang implements the pre-FDIS rule, under which DefaultedDefCtor2's
+// default constructor is non-trivial.
+union NotDeleted1b { DefaultedDefCtor2 nu; }; // unexpected-note {{deleted here}}
+NotDeleted1b nd1b; // unexpected-error {{deleted constructor}}
+
+// - any non-static data member with no brace-or-equal-initializer is of
+// reference type,
+class Deleted2a { Deleted2a() = default; int &a; }; // expected-note {{deleted here}}
+Deleted2a d2a; // expected-error {{deleted constructor}}
+class NotDeleted2a { int &a = n; };
+NotDeleted2a nd2a;
+class NotDeleted2b { int &a = error; }; // expected-error {{undeclared identifier}}
+NotDeleted2b nd2b;
+
+// - any non-variant non-static data member of const qualified type (or array
+// thereof) with no brace-or-equal-initializer does not have a user-provided
+// default constructor,
+class Deleted3a { const int a; }; // expected-note {{here}} \
+ expected-warning {{does not declare any constructor}} \
+ expected-note {{will never be initialized}}
+Deleted3a d3a; // expected-error {{deleted constructor}}
+class Deleted3b { const DefaultedDefCtor1 a[42]; }; // expected-note {{here}}
+Deleted3b d3b; // expected-error {{deleted constructor}}
+// FIXME: clang implements the pre-FDIS rule, under which DefaultedDefCtor2's
+// default constructor is user-provided.
+class Deleted3c { const DefaultedDefCtor2 a; }; // desired-note {{here}}
+Deleted3c d3c; // desired-error {{deleted constructor}}
+class NotDeleted3a { const int a = 0; };
+NotDeleted3a nd3a;
+class NotDeleted3b { const DefaultedDefCtor1 a[42] = {}; };
+NotDeleted3b nd3b;
+class NotDeleted3c { const DefaultedDefCtor2 a = DefaultedDefCtor2(); };
+NotDeleted3c nd3c;
+union NotDeleted3d { const int a; int b; };
+NotDeleted3d nd3d;
+// FIXME: this class should not have a deleted default constructor.
+union NotDeleted3e { const DefaultedDefCtor1 a[42]; int b; }; // unexpected-note {{here}}
+NotDeleted3e nd3e; // unexpected-error {{deleted constructor}}
+// FIXME: clang implements the pre-FDIS rule, under which DefaultedDefCtor2 is
+// non-trivial.
+union NotDeleted3f { const DefaultedDefCtor2 a; int b; }; // unexpected-note {{here}}
+NotDeleted3f nd3f; // unexpected-error {{deleted constructor}}
+
+// - X is a union and all of its variant members are of const-qualified type (or
+// array thereof),
+union Deleted4a { const int a; const int b; const UserProvidedDefCtor c; }; // expected-note {{here}}
+Deleted4a d4a; // expected-error {{deleted constructor}}
+union Deleted4b { const int a; int b; };
+Deleted4b d4b;
+
+// - X is a non-union class and all members of any anonymous union member are of
+// const-qualified type (or array thereof),
+struct Deleted5a { union { const int a; }; union { int b; }; }; // expected-note {{here}}
+Deleted5a d5a; // expected-error {{deleted constructor}}
+struct Deleted5b { union { const int a; int b; }; union { const int c; int d; }; };
+Deleted5b d5b;
+
+// - any direct or virtual base class, or non-static data member with no
+// brace-or-equal-initializer, has class type M (or array thereof) and either
+// M has no default constructor or overload resolution as applied to M's default
+// constructor results in an ambiguity or in a function that is deleted or
+// inaccessible from the defaulted default constructor, or
+struct Deleted6a : Deleted2a {}; // expected-note {{here}}
+Deleted6a d6a; // expected-error {{deleted constructor}}
+struct Deleted6b : virtual Deleted2a {}; // expected-note {{here}}
+Deleted6b d6b; // expected-error {{deleted constructor}}
+struct Deleted6c { Deleted2a a; }; // expected-note {{here}}
+Deleted6c d6c; // expected-error {{deleted constructor}}
+struct Deleted6d { DeletedDefCtor a; }; // expected-note {{here}}
+Deleted6d d6d; // expected-error {{deleted constructor}}
+struct NotDeleted6a { DeletedDefCtor a = 0; };
+NotDeleted6a nd6a;
+struct Deleted6e { PrivateDefCtor a; }; // expected-note {{here}}
+Deleted6e d6e; // expected-error {{deleted constructor}}
+struct NotDeleted6b { PrivateDefCtor a = 0; };
+NotDeleted6b nd6b;
+struct NotDeleted6c { Friend a; };
+NotDeleted6c nd6c;
+
+// - any direct or virtual base class or non-static data member has a type with
+// a destructor that is deleted or inaccessible from the defaulted default
+// constructor.
+struct Deleted7a : DeletedDtor {}; // expected-note {{here}}
+Deleted7a d7a; // expected-error {{deleted constructor}}
+struct Deleted7b : virtual DeletedDtor {}; // expected-note {{here}}
+Deleted7b d7b; // expected-error {{deleted constructor}}
+struct Deleted7c { DeletedDtor a; }; // expected-note {{here}}
+Deleted7c d7c; // expected-error {{deleted constructor}}
+struct Deleted7d { DeletedDtor a = {}; }; // expected-note {{here}}
+Deleted7d d7d; // expected-error {{deleted constructor}}
+struct Deleted7e : PrivateDtor {}; // expected-note {{here}}
+Deleted7e d7e; // expected-error {{deleted constructor}}
+struct Deleted7f : virtual PrivateDtor {}; // expected-note {{here}}
+Deleted7f d7f; // expected-error {{deleted constructor}}
+struct Deleted7g { PrivateDtor a; }; // expected-note {{here}}
+Deleted7g d7g; // expected-error {{deleted constructor}}
+struct Deleted7h { PrivateDtor a = {}; }; // expected-note {{here}}
+Deleted7h d7h; // expected-error {{deleted constructor}}
+struct NotDeleted7i : Friend {};
+NotDeleted7i d7i;
+struct NotDeleted7j : virtual Friend {};
+NotDeleted7j d7j;
+struct NotDeleted7k { Friend a; };
+NotDeleted7k d7k;
+
+
+class Trivial { static const int n = 42; };
+static_assert(__has_trivial_constructor(Trivial), "Trivial is nontrivial");
+
+// A default constructor is trivial if it is not user-provided and if:
+class NonTrivialDefCtor1 { NonTrivialDefCtor1(); };
+static_assert(!__has_trivial_constructor(NonTrivialDefCtor1), "NonTrivialDefCtor1 is trivial");
+
+// - its class has no virtual functions (10.3) and no virtual base classes (10.1), and
+class NonTrivialDefCtor2 { virtual void f(); };
+static_assert(!__has_trivial_constructor(NonTrivialDefCtor2), "NonTrivialDefCtor2 is trivial");
+class NonTrivialDefCtor3 : virtual Trivial {};
+static_assert(!__has_trivial_constructor(NonTrivialDefCtor3), "NonTrivialDefCtor3 is trivial");
+
+// - no non-static data member of its class has a brace-or-equal-initializer, and
+class NonTrivialDefCtor4 { int m = 52; };
+static_assert(!__has_trivial_constructor(NonTrivialDefCtor4), "NonTrivialDefCtor4 is trivial");
+
+// - all the direct base classes of its class have trivial default constructors, and
+class NonTrivialDefCtor5 : NonTrivialDefCtor1 {};
+static_assert(!__has_trivial_constructor(NonTrivialDefCtor5), "NonTrivialDefCtor5 is trivial");
+
+// - for all the non-static data members of its class that are of class type (or array thereof), each such class
+// has a trivial default constructor.
+class NonTrivialDefCtor6 { NonTrivialDefCtor1 t; };
+static_assert(!__has_trivial_constructor(NonTrivialDefCtor6), "NonTrivialDefCtor5 is trivial");
+
+// Otherwise, the default constructor is non-trivial.
+class Trivial2 { Trivial2() = delete; };
+//static_assert(__has_trivial_constructor(Trivial2), "NonTrivialDefCtor2 is trivial");
+// FIXME: clang implements the pre-FDIS rule, under which this class is non-trivial.
+static_assert(!__has_trivial_constructor(Trivial2), "NonTrivialDefCtor2 is trivial");
+
+class Trivial3 { Trivial3() = default; };
+//static_assert(__has_trivial_constructor(Trivial3), "NonTrivialDefCtor3 is trivial");
+// FIXME: clang implements the pre-FDIS rule, under which this class is non-trivial.
+static_assert(!__has_trivial_constructor(Trivial3), "NonTrivialDefCtor3 is trivial");
diff --git a/test/CXX/special/class.dtor/p3-0x.cpp b/test/CXX/special/class.dtor/p3-0x.cpp
new file mode 100644
index 0000000..6cdd167
--- /dev/null
+++ b/test/CXX/special/class.dtor/p3-0x.cpp
@@ -0,0 +1,177 @@
+// RUN: %clang_cc1 -std=c++0x -fexceptions -fcxx-exceptions -emit-llvm -o - %s | FileCheck %s
+
+struct A {
+ ~A();
+};
+
+struct B {
+ ~B() throw(int);
+};
+
+struct C {
+ B b;
+ ~C() {}
+};
+
+struct D {
+ ~D() noexcept(false);
+};
+
+struct E {
+ D d;
+ ~E() {}
+};
+
+void foo() {
+ A a;
+ C c;
+ E e;
+ // CHECK: invoke {{.*}} @_ZN1ED1Ev
+ // CHECK: invoke {{.*}} @_ZN1CD1Ev
+ // CHECK: call {{.*}} @_ZN1AD1Ev
+}
+
+struct F {
+ D d;
+ ~F();
+};
+F::~F() noexcept(false) {}
+
+struct G {
+ D d;
+ ~G();
+};
+G::~G() {}
+
+struct H {
+ B b;
+ ~H();
+};
+H::~H() throw(int) {}
+
+struct I {
+ B b;
+ ~I();
+};
+I::~I() {}
+
+// Template variants.
+
+template <typename T>
+struct TA {
+ ~TA();
+};
+
+template <typename T>
+struct TB {
+ ~TB() throw(int);
+};
+
+template <typename T>
+struct TC {
+ TB<T> b;
+ ~TC() {}
+};
+
+template <typename T>
+struct TD {
+ ~TD() noexcept(false);
+};
+
+template <typename T>
+struct TE {
+ TD<T> d;
+ ~TE() {}
+};
+
+void tfoo() {
+ TA<int> a;
+ TC<int> c;
+ TE<int> e;
+ // CHECK: invoke {{.*}} @_ZN2TEIiED1Ev
+ // CHECK: invoke {{.*}} @_ZN2TCIiED1Ev
+ // CHECK: call {{.*}} @_ZN2TAIiED1Ev
+}
+
+template <typename T>
+struct TF {
+ TD<T> d;
+ ~TF();
+};
+template <typename T>
+TF<T>::~TF() noexcept(false) {}
+
+template <typename T>
+struct TG {
+ TD<T> d;
+ ~TG();
+};
+template <typename T>
+TG<T>::~TG() {}
+
+template <typename T>
+struct TH {
+ TB<T> b;
+ ~TH();
+};
+template <typename T>
+TH<T>::~TH() {}
+
+void tinst() {
+ TF<int> f;
+ TG<int> g;
+ TH<int> h;
+}
+// CHECK: define linkonce_odr {{.*}} @_ZN2THIiED1Ev
+// CHECK: _ZTIi
+// CHECK: __cxa_call_unexpected
+
+struct VX
+{ virtual ~VX() {} };
+
+struct VY : VX
+{ virtual ~VY() {} };
+
+template<typename T>
+struct TVY : VX
+{ virtual ~TVY() {} };
+
+
+struct VA {
+ B b;
+ virtual ~VA() {}
+};
+
+struct VB : VA
+{ virtual ~VB() {} };
+
+template<typename T>
+struct TVB : VA
+{ virtual ~TVB() {} };
+
+void tinst2() {
+ TVY<int> tvy;
+ TVB<int> tvb;
+}
+
+template <typename T>
+struct Sw {
+ T t;
+ ~Sw() {}
+};
+
+void tsw() {
+ Sw<int> swi;
+ Sw<B> swb;
+}
+// CHECK-NOT: define linkonce_odr {{.*}} @_ZN2SwI1BED1Ev({{.*}} nounwind
+// CHECK: define linkonce_odr {{.*}} @_ZN2SwI1BED1Ev({{.*}}
+// CHECK: _ZTIi
+// CHECK: __cxa_call_unexpected
+// CHECK: define linkonce_odr {{.*}} @_ZN2SwIiED1Ev({{.*}} nounwind
+
+template <typename T>
+struct TVC : VX
+{ virtual ~TVC(); };
+template <typename T>
+TVC<T>::~TVC() {}
diff --git a/test/CXX/special/class.init/class.base.init/p8-0x.cpp b/test/CXX/special/class.init/class.base.init/p8-0x.cpp
new file mode 100644
index 0000000..8512a9f
--- /dev/null
+++ b/test/CXX/special/class.init/class.base.init/p8-0x.cpp
@@ -0,0 +1,23 @@
+// RUN: %clang_cc1 -std=c++0x -fsyntax-only -verify %s
+
+int n;
+struct S {
+ int &a; // expected-note 2{{here}}
+ int &b = n;
+
+ S() {} // expected-error {{constructor for 'S' must explicitly initialize the reference member 'a'}}
+ S(int) : a(n) {} // ok
+ S(char) : b(n) {} // expected-error {{constructor for 'S' must explicitly initialize the reference member 'a'}}
+ S(double) : a(n), b(n) {} // ok
+};
+
+union U {
+ int a = 0;
+ char b = 'x';
+
+ // FIXME: these should all be rejected
+ U() {} // desired-error {{at most one member of a union may be initialized}}
+ U(int) : a(1) {} // desired-error {{at most one member of a union may be initialized}}
+ U(char) : b('y') {} // desired-error {{at most one member of a union may be initialized}}
+ U(double) : a(1), b('y') {} // desired-error {{at most one member of a union may be initialized}}
+};
diff --git a/test/CXX/special/class.init/class.base.init/p9-0x.cpp b/test/CXX/special/class.init/class.base.init/p9-0x.cpp
new file mode 100644
index 0000000..039b1c2
--- /dev/null
+++ b/test/CXX/special/class.init/class.base.init/p9-0x.cpp
@@ -0,0 +1,36 @@
+// RUN: %clang_cc1 -triple x86_64-pc-linux-gnu -std=c++0x %s -O1 -emit-llvm -o - | FileCheck %s
+
+struct S {
+ int n = 10;
+ int m = 2 * n;
+
+ S() {}
+ S(int a) : n(a) {}
+ S(int a, int b) : n(a), m(b) {}
+
+ struct T {
+ T *that = this;
+ };
+};
+
+template<typename T>
+struct U {
+ T *r = &q;
+ T q = 42;
+ U *p = this;
+};
+
+S a;
+// CHECK: @a = {{.*}} { i32 10, i32 20 }
+
+S b(5);
+// CHECK: @b = {{.*}} { i32 5, i32 10 }
+
+S c(3, 9);
+// CHECK: @c = {{.*}} { i32 3, i32 9 }
+
+S::T d;
+// CHECK: @d = {{.*}} { {{.*}} @d }
+
+U<S> e;
+// CHECK: @e = {{.*}} { {{.*}} { i32 42, i32 84 }, {{.*}} @e }
diff --git a/test/CXX/stmt.stmt/stmt.dcl/p3-0x.cpp b/test/CXX/stmt.stmt/stmt.dcl/p3-0x.cpp
new file mode 100644
index 0000000..b415044
--- /dev/null
+++ b/test/CXX/stmt.stmt/stmt.dcl/p3-0x.cpp
@@ -0,0 +1,55 @@
+// RUN: %clang_cc1 -std=c++0x -fsyntax-only -verify %s
+
+// PR10034
+struct X {};
+
+void exx(X) {}
+
+int test_ptr10034(int argc, char **argv)
+{
+ if (argc > 3)
+ goto end;
+
+ X x;
+ X xs[16];
+ exx(x);
+
+ end:
+ if (argc > 1) {
+ for (int i = 0; i < argc; ++i)
+ {
+
+ }
+ }
+ return 0;
+}
+
+struct Y {
+ ~Y();
+};
+
+void f();
+void test_Y() {
+ goto end;
+ Y y;
+ end:
+ f();
+ goto inner;
+ {
+ Y y2;
+ inner:
+ f();
+ }
+ return;
+}
+
+struct Z {
+ Z operator=(const Z&);
+};
+
+void test_Z() {
+ goto end;
+ Z z;
+ end:
+ return;
+}
diff --git a/test/CXX/stmt.stmt/stmt.dcl/p3.cpp b/test/CXX/stmt.stmt/stmt.dcl/p3.cpp
new file mode 100644
index 0000000..18fd340
--- /dev/null
+++ b/test/CXX/stmt.stmt/stmt.dcl/p3.cpp
@@ -0,0 +1,47 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s
+
+// PR10034
+struct X {};
+
+void exx(X) {}
+
+int test_ptr10034(int argc, char **argv)
+{
+ if (argc > 3)
+ goto end;
+
+ X x;
+ X xs[16];
+ exx(x);
+
+ end:
+ if (argc > 1) {
+ for (int i = 0; i < argc; ++i)
+ {
+
+ }
+ }
+ return 0;
+}
+
+struct Y {
+ ~Y();
+};
+
+void test_Y() {
+ goto end; // expected-error{{goto into protected scope}}
+ Y y; // expected-note{{jump bypasses variable initialization}}
+ end:
+ return;
+}
+
+struct Z {
+ Z operator=(const Z&);
+};
+
+void test_Z() {
+ goto end; // expected-error{{goto into protected scope}}
+ Z z; // expected-note{{jump bypasses variable initialization}}
+ end:
+ return;
+}
diff --git a/test/CXX/stmt.stmt/stmt.iter/stmt.ranged/p1.cpp b/test/CXX/stmt.stmt/stmt.iter/stmt.ranged/p1.cpp
index 12acde1..7bfa6fe 100644
--- a/test/CXX/stmt.stmt/stmt.iter/stmt.ranged/p1.cpp
+++ b/test/CXX/stmt.stmt/stmt.iter/stmt.ranged/p1.cpp
@@ -33,8 +33,8 @@ struct B {
int *alt_end();
};
-void f(); // expected-note {{candidate}}
-void f(int); // expected-note {{candidate}}
+void f();
+void f(int);
void g() {
for (int a : A())
@@ -44,7 +44,7 @@ void g() {
for (char *a : B()) { // expected-error {{cannot initialize a variable of type 'char *' with an lvalue of type 'int'}}
}
// FIXME: Terrible diagnostic here. auto deduction should fail, but does not!
- for (double a : f) { // expected-error {{address of overloaded function 'f' does not match required type '<overloaded function type>'}}
+ for (double a : f) { // expected-error {{cannot use type '<overloaded function type>' as a range}}
}
for (auto a : A()) {
}
diff --git a/test/CXX/temp/temp.decls/p3.cpp b/test/CXX/temp/temp.decls/p3.cpp
new file mode 100644
index 0000000..54800e4
--- /dev/null
+++ b/test/CXX/temp/temp.decls/p3.cpp
@@ -0,0 +1,7 @@
+// RUN: %clang_cc1 -std=c++0x -fsyntax-only -verify %s
+
+template<typename T> using A = int;
+template<typename T> using A<T*> = char; // expected-error {{partial specialization of alias templates is not permitted}}
+template<> using A<char> = char; // expected-error {{explicit specialization of alias templates is not permitted}}
+template using A<char> = char; // expected-error {{explicit instantiation of alias templates is not permitted}}
+using A<char> = char; // expected-error {{name defined in alias declaration must be an identifier}}
diff --git a/test/CXX/temp/temp.decls/temp.alias/p1.cpp b/test/CXX/temp/temp.decls/temp.alias/p1.cpp
new file mode 100644
index 0000000..80079b3
--- /dev/null
+++ b/test/CXX/temp/temp.decls/temp.alias/p1.cpp
@@ -0,0 +1,8 @@
+// RUN: %clang_cc1 -std=c++0x -fsyntax-only -verify %s
+
+template<typename T> using U = T;
+
+// The name of the alias template is a template-name.
+U<char> x;
+void f(U<int>);
+typedef U<U<U<U<int>>>> I;
diff --git a/test/CXX/temp/temp.decls/temp.alias/p2.cpp b/test/CXX/temp/temp.decls/temp.alias/p2.cpp
new file mode 100644
index 0000000..e145727
--- /dev/null
+++ b/test/CXX/temp/temp.decls/temp.alias/p2.cpp
@@ -0,0 +1,45 @@
+// RUN: %clang_cc1 -std=c++0x -fsyntax-only -verify %s
+
+template<typename T> using U = T;
+
+using I = U<U<U<U<int>>>>;
+using I = int;
+
+template<typename A, typename B> using Fst = A;
+template<typename A, typename B> using Snd = B;
+
+using I = Fst<Snd<char,int>,double>;
+
+namespace StdExample {
+ // Prerequisites for example.
+ template<class T, class A> struct vector { /* ... */ };
+
+
+ template<class T> struct Alloc {};
+ template<class T> using Vec = vector<T, Alloc<T>>;
+ Vec<int> v;
+
+ template<class T>
+ void process(Vec<T>& v) // expected-note {{previous definition is here}}
+ { /* ... */ }
+
+ template<class T>
+ void process(vector<T, Alloc<T>>& w) // expected-error {{redefinition of 'process'}}
+ { /* ... */ }
+
+ template<template<class> class TT>
+ void f(TT<int>); // expected-note {{candidate template ignored}}
+
+ template<template<class,class> class TT>
+ void g(TT<int, Alloc<int>>);
+
+ int h() {
+ f(v); // expected-error {{no matching function for call to 'f'}}
+ g(v); // OK: TT = vector
+ }
+
+
+ // v's type is same as vector<int, Alloc<int>>.
+ using VTest = vector<int, Alloc<int>>;
+ using VTest = decltype(v);
+}
diff --git a/test/CXX/temp/temp.decls/temp.alias/p3.cpp b/test/CXX/temp/temp.decls/temp.alias/p3.cpp
new file mode 100644
index 0000000..2e9e55c
--- /dev/null
+++ b/test/CXX/temp/temp.decls/temp.alias/p3.cpp
@@ -0,0 +1,13 @@
+// RUN: %clang_cc1 -std=c++0x -fsyntax-only -verify %s
+
+// The example given in the standard (this is rejected for other reasons anyway).
+template<class T> struct A;
+template<class T> using B = typename A<T>::U; // expected-error {{no type named 'U' in 'A<T>'}}
+template<class T> struct A {
+ typedef B<T> U; // expected-note {{in instantiation of template type alias 'B' requested here}}
+};
+B<short> b;
+
+template<typename T> using U = int;
+// FIXME: This is illegal, but probably only because CWG1044 missed this paragraph.
+template<typename T> using U = U<T>;
diff --git a/test/CXX/temp/temp.decls/temp.friend/p3.cpp b/test/CXX/temp/temp.decls/temp.friend/p3.cpp
index d116e01..0b2a25e 100644
--- a/test/CXX/temp/temp.decls/temp.friend/p3.cpp
+++ b/test/CXX/temp/temp.decls/temp.friend/p3.cpp
@@ -8,5 +8,5 @@ class B {
template <class T> friend class A;
template <class T> friend class Undeclared;
- template <class T> friend typename A<T>::Member; // expected-warning {{non-class type 'typename A<T>::Member' cannot be a friend}}
+ template <class T> friend typename A<T>::Member; // expected-error {{friend type templates must use an elaborated type}}
};
diff --git a/test/CXX/temp/temp.decls/temp.variadic/ext-blocks.cpp b/test/CXX/temp/temp.decls/temp.variadic/ext-blocks.cpp
index 62cf429..7375f98 100644
--- a/test/CXX/temp/temp.decls/temp.variadic/ext-blocks.cpp
+++ b/test/CXX/temp/temp.decls/temp.variadic/ext-blocks.cpp
@@ -37,3 +37,10 @@ int f3(Args ...args) {
}
template int f3(const char*, int, float, double);
+
+template<typename ...Args>
+int PR9953(Args ...args) {
+ return ^(Args *...block_args) {
+ return f1(block_args); // expected-error{{expression contains unexpanded parameter pack 'block_args'}}
+ }(&args...);
+}
diff --git a/test/CXX/temp/temp.fct.spec/temp.deduct/cwg1170.cpp b/test/CXX/temp/temp.fct.spec/temp.deduct/cwg1170.cpp
new file mode 100644
index 0000000..d3af0d4
--- /dev/null
+++ b/test/CXX/temp/temp.fct.spec/temp.deduct/cwg1170.cpp
@@ -0,0 +1,41 @@
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++0x %s
+
+#if !__has_feature(cxx_access_control_sfinae)
+# error No support for access control as part of SFINAE?
+#endif
+
+typedef char yes_type;
+typedef char (&no_type)[2];
+
+template<unsigned N> struct unsigned_c { };
+
+template<typename T>
+class has_copy_constructor {
+ static T t;
+
+ template<typename U> static yes_type check(unsigned_c<sizeof(U(t))> * = 0);
+ template<typename U> static no_type check(...);
+
+public:
+ static const bool value = (sizeof(check<T>(0)) == sizeof(yes_type));
+};
+
+struct HasCopy { };
+
+struct HasNonConstCopy {
+ HasNonConstCopy(HasNonConstCopy&);
+};
+
+struct HasDeletedCopy {
+ HasDeletedCopy(const HasDeletedCopy&) = delete;
+};
+
+struct HasPrivateCopy {
+private:
+ HasPrivateCopy(const HasPrivateCopy&);
+};
+
+int check0[has_copy_constructor<HasCopy>::value? 1 : -1];
+int check1[has_copy_constructor<HasNonConstCopy>::value? 1 : -1];
+int check2[has_copy_constructor<HasDeletedCopy>::value? -1 : 1];
+int check3[has_copy_constructor<HasPrivateCopy>::value? -1 : 1];
diff --git a/test/CXX/temp/temp.param/p10-0x.cpp b/test/CXX/temp/temp.param/p10-0x.cpp
new file mode 100644
index 0000000..bc7e616
--- /dev/null
+++ b/test/CXX/temp/temp.param/p10-0x.cpp
@@ -0,0 +1,13 @@
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++0x %s
+
+template<typename> struct Y1;
+template<typename, int> struct Y2;
+
+template<class T1, class T2 = int> using B2 = T1;
+template<class T1 = int, class T2> using B2 = T1;
+
+template<template<class> class F, template<class> class G = Y1> using B2t = F<G<int>>;
+template<template<class> class F = Y2, template<class> class G> using B2t = F<G<int>>;
+
+template<int N, int M = 5> using B2n = Y2<int, N + M>;
+template<int N = 5, int M> using B2n = Y2<int, N + M>;
diff --git a/test/CXX/temp/temp.param/p11-0x.cpp b/test/CXX/temp/temp.param/p11-0x.cpp
index 0bf4341..10a4438 100644
--- a/test/CXX/temp/temp.param/p11-0x.cpp
+++ b/test/CXX/temp/temp.param/p11-0x.cpp
@@ -1,29 +1,48 @@
// RUN: %clang_cc1 -std=c++0x -fsyntax-only -verify %s
-// If a template-parameter of a class template has a default
-// template-argument, each subsequent template-parameter shall either
-// have a default template-argument supplied or be a template
-// parameter pack.
+// If a template-parameter of a class template or alias template has a default
+// template-argument, each subsequent template-parameter shall either have a
+// default template-argument supplied or be a template parameter pack.
template<typename> struct vector;
+template<typename T = int, typename> struct X3t; // expected-error{{template parameter missing a default argument}} expected-note{{previous default template argument defined here}}
+template<typename T = int, typename> using A3t = int; // expected-error{{template parameter missing a default argument}} expected-note{{previous default template argument defined here}}
+template<int V = 0, int> struct X3nt; // expected-error{{template parameter missing a default argument}} expected-note{{previous default template argument defined here}}
+template<int V = 0, int> using A3nt = int; // expected-error{{template parameter missing a default argument}} expected-note{{previous default template argument defined here}}
+template<template<class> class M = vector, template<class> class> struct X3tt; // expected-error{{template parameter missing a default argument}} expected-note{{previous default template argument defined here}}
+template<template<class> class M = vector, template<class> class> using A3tt = int; // expected-error{{template parameter missing a default argument}} expected-note{{previous default template argument defined here}}
+
template<typename T = int, typename ...Types> struct X2t;
+template<typename T = int, typename ...Types> using A2t = X2t<T, Types...>;
template<int V = 0, int ...Values> struct X2nt;
+template<int V = 0, int ...Values> using A2nt = X2nt<V, Values...>;
template<template<class> class M = vector, template<class> class... Metas>
struct X2tt;
+template<template<class> class M = vector, template<class> class... Metas>
+ using A2tt = X2tt<M, Metas...>;
-// If a template-parameter of a primary class template is a template
-// parameter pack, it shall be the last template-parameter .
+// If a template-parameter of a primary class template or alias template is a
+// template parameter pack, it shall be the last template-parameter.
template<typename ...Types, // expected-error{{template parameter pack must be the last template parameter}}
int After>
struct X0t;
+template<typename ...Types, // expected-error{{template parameter pack must be the last template parameter}}
+ int After>
+using A0t = int;
template<int ...Values, // expected-error{{template parameter pack must be the last template parameter}}
int After>
struct X0nt;
+template<int ...Values, // expected-error{{template parameter pack must be the last template parameter}}
+ int After>
+using A0nt = int;
template<template<typename> class ...Templates, // expected-error{{template parameter pack must be the last template parameter}}
int After>
struct X0tt;
+template<template<typename> class ...Templates, // expected-error{{template parameter pack must be the last template parameter}}
+ int After>
+using A0tt = int;
// [ Note: These are not requirements for function templates or class
// template partial specializations because template arguments can be
diff --git a/test/CXX/temp/temp.param/p9-0x.cpp b/test/CXX/temp/temp.param/p9-0x.cpp
index 17eca7f..1dc6640 100644
--- a/test/CXX/temp/temp.param/p9-0x.cpp
+++ b/test/CXX/temp/temp.param/p9-0x.cpp
@@ -50,3 +50,12 @@ namespace PR8748 {
template<typename T = int> struct Inner::X3 { };
template<typename T = int> void Inner::f2() {}
}
+
+namespace PR10069 {
+ template<typename T, T a, T b=0, T c=1>
+ T f(T x);
+
+ void g() {
+ f<unsigned int, 0>(0);
+ }
+}
diff --git a/test/CXX/temp/temp.res/temp.dep/temp.dep.type/p1.cpp b/test/CXX/temp/temp.res/temp.dep/temp.dep.type/p1.cpp
new file mode 100644
index 0000000..1d1d350
--- /dev/null
+++ b/test/CXX/temp/temp.res/temp.dep/temp.dep.type/p1.cpp
@@ -0,0 +1,30 @@
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++0x %s
+
+// Examples from CWG1056.
+namespace Example1 {
+ template<class T> struct A;
+ template<class T> using B = A<T>;
+
+ template<class T> struct A {
+ struct C {};
+ B<T>::C bc; // ok, B<T> is the current instantiation.
+ };
+
+ template<class T> struct A<A<T>> {
+ struct C {};
+ B<B<T>>::C bc; // ok, B<B<T>> is the current instantiation.
+ };
+
+ template<class T> struct A<A<A<T>>> {
+ struct C {};
+ B<B<T>>::C bc; // expected-error {{missing 'typename'}}
+ };
+}
+
+namespace Example2 {
+ template<class T> struct A {
+ void g();
+ };
+ template<class T> using B = A<T>;
+ template<class T> void B<T>::g() {} // ok.
+}
diff --git a/test/CXX/temp/temp.spec/temp.expl.spec/examples.cpp b/test/CXX/temp/temp.spec/temp.expl.spec/examples.cpp
new file mode 100644
index 0000000..f04c544
--- /dev/null
+++ b/test/CXX/temp/temp.spec/temp.expl.spec/examples.cpp
@@ -0,0 +1,209 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s
+
+namespace PR5907 {
+ template<typename T> struct identity { typedef T type; };
+ struct A { A(); };
+ identity<A>::type::A() { }
+
+ struct B { void f(); };
+ template<typename T> struct C { typedef B type; };
+
+ void C<int>::type::f() { }
+}
+
+namespace PR9421 {
+ namespace N { template<typename T> struct S { void f(); }; }
+ typedef N::S<int> T;
+ namespace N { template<> void T::f() {} }
+}
+
+namespace PR8277 {
+ template< typename S >
+ struct C
+ {
+ template< int >
+ void F( void )
+ {
+ }
+ };
+
+ template< typename S >
+ struct D
+ {
+ typedef C< int > A;
+ };
+
+ typedef D< int >::A A;
+
+ template<>
+ template<>
+ void A::F< 0 >( void )
+ {
+ }
+}
+
+namespace PR8277b {
+ template<typename S> struct C {
+ void f();
+ };
+ template<typename S> struct D {
+ typedef C<int> A;
+ };
+ template<> void D<int>::A::f() {
+ }
+}
+
+namespace PR8708 {
+ template<typename T> struct A {
+ template<typename U> struct B {
+ // #2
+ void f();
+ };
+ };
+
+ // #A specialize the member template for
+ // implicit instantiation of A<int>,
+ // leaving the member template "unspecialized"
+ // (14.7.3/16). Specialization uses the syntax
+ // for explicit specialization (14.7.3/14)
+ template<> template<typename U>
+ struct A<int>::B {
+ // #1
+ void g();
+ };
+
+ // #1 define its function g. There is an enclosing
+ // class template, so we write template<> for each
+ // specialized template (14.7.3/15).
+ template<> template<typename U>
+ void A<int>::B<U>::g() { }
+
+ // #2 define the unspecialized member template's
+ // f
+ template<typename T> template<typename U>
+ void A<T>::B<U>::f() { }
+
+
+ // specialize the member template again, now
+ // specializing the member too. This specializes
+ // #A
+ template<> template<>
+ struct A<int>::B<int> {
+ // #3
+ void h();
+ };
+
+ // defines #3. There is no enclosing class template, so
+ // we write no "template<>".
+ void A<int>::B<int>::h() { }
+
+ void test() {
+ // calls #1
+ A<int>::B<float> a; a.g();
+
+ // calls #2
+ A<float>::B<int> b; b.f();
+
+ // calls #3
+ A<int>::B<int> c; c.h();
+ }
+}
+
+namespace PR9482 {
+ namespace N1 {
+ template <typename T> struct S {
+ void foo() {}
+ };
+ }
+
+ namespace N2 {
+ typedef N1::S<int> X;
+ }
+
+ namespace N1 {
+ template<> void N2::X::foo() {}
+ }
+}
+
+namespace PR9668 {
+ namespace First
+ {
+ template<class T>
+ class Bar
+ {
+ protected:
+
+ static const bool static_bool;
+ };
+ }
+
+ namespace Second
+ {
+ class Foo;
+ }
+
+ typedef First::Bar<Second::Foo> Special;
+
+ namespace
+ First
+ {
+ template<>
+ const bool Special::static_bool(false);
+ }
+}
+
+namespace PR9877 {
+ template<int>
+ struct X
+ {
+ struct Y;
+ };
+
+ template<> struct X<0>::Y { static const int Z = 1; };
+ template<> struct X<1>::Y { static const int Z = 1; };
+
+ const int X<0>::Y::Z;
+ template<> const int X<1>::Y::Z; // expected-error{{extraneous 'template<>' in declaration of variable 'Z'}}
+}
+
+namespace PR9913 {
+ template<class,class=int>struct S;
+ template<class X>struct S<X> {
+ template<class T> class F;
+ };
+
+ template<class A>
+ template<class B>
+ class S<A>::F{};
+}
+
+namespace template_class_spec_perClassDecl_nested
+{
+ template <typename T1> struct A {
+ template <typename T2> struct B {
+ template <typename T3> struct C {
+ static void foo();
+ };
+ };
+ };
+
+ template <> struct A<int> {
+ template <typename T2> struct B {
+ template <typename T3> struct C {
+ static void foo();
+ };
+ };
+ };
+
+ template <> template <typename T3> struct A<int>::B<int>::C {
+ static void foo();
+ };
+
+ template <> template <> struct A<int>::B<int>::C<int> {
+ static void foo();
+ };
+
+ template <> template<> template <typename T2> struct A<bool>::B<bool>::C {
+ static void foo();
+ };
+}
diff --git a/test/CXX/temp/temp.spec/temp.expl.spec/p15.cpp b/test/CXX/temp/temp.spec/temp.expl.spec/p15.cpp
index a5ecf5fc..72f33df 100644
--- a/test/CXX/temp/temp.spec/temp.expl.spec/p15.cpp
+++ b/test/CXX/temp/temp.spec/temp.expl.spec/p15.cpp
@@ -20,3 +20,14 @@ NonDefaultConstructible &test(bool b) {
return b? X<NonDefaultConstructible, int>::member // expected-note{{instantiation}}
: X<NonDefaultConstructible, long>::member;
}
+
+namespace rdar9422013 {
+ template<int>
+ struct X {
+ struct Inner {
+ static unsigned array[17];
+ };
+ };
+
+ template<> unsigned X<1>::Inner::array[]; // okay
+}
diff --git a/test/CXX/temp/temp.spec/temp.expl.spec/p16.cpp b/test/CXX/temp/temp.spec/temp.expl.spec/p16.cpp
index 2f9a3cb..c7597e9 100644
--- a/test/CXX/temp/temp.spec/temp.expl.spec/p16.cpp
+++ b/test/CXX/temp/temp.spec/temp.expl.spec/p16.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only %s
+// RUN: %clang_cc1 -fsyntax-only -verify %s
template<class T> struct A {
void f(T);
template<class X1> void g1(T, X1);
@@ -24,3 +24,15 @@ template<> template<>
// member specialization even if defined in class definition
template<> void A<int>::h(int) { }
+
+namespace PR10024 {
+ template <typename T>
+ struct Test{
+ template <typename U>
+ void get(U i) {}
+ };
+
+ template <typename T>
+ template <>
+ void Test<T>::get<double>(double i) {} // expected-error{{cannot specialize (with 'template<>') a member of an unspecialized template}}
+}
diff --git a/test/CXX/temp/temp.spec/temp.expl.spec/p17.cpp b/test/CXX/temp/temp.spec/temp.expl.spec/p17.cpp
index 88cfc5d..56231e2 100644
--- a/test/CXX/temp/temp.spec/temp.expl.spec/p17.cpp
+++ b/test/CXX/temp/temp.spec/temp.expl.spec/p17.cpp
@@ -24,12 +24,11 @@ namespace test1 {
template <> class A<double> {
public:
- static int foo; // expected-note{{attempt to specialize}}
+ static int foo;
static int bar;
};
typedef A<double> AB;
- template <> int AB::foo = 0; // expected-error{{extraneous 'template<>'}} \
- // expected-error{{does not specialize}}
+ template <> int AB::foo = 0; // expected-error{{extraneous 'template<>'}}
int AB::bar = 1;
}
diff --git a/test/CXX/temp/temp.spec/temp.expl.spec/p5-example.cpp b/test/CXX/temp/temp.spec/temp.expl.spec/p5-example.cpp
new file mode 100644
index 0000000..f49190e
--- /dev/null
+++ b/test/CXX/temp/temp.spec/temp.expl.spec/p5-example.cpp
@@ -0,0 +1,34 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s
+template<class T> struct A {
+ struct B { };
+ template<class U> struct C { };
+};
+ template<> struct A<int> {
+ void f(int);
+};
+void h() {
+ A<int> a;
+ a.f(16);
+}
+// A<int>::f must be defined somewhere
+// template<> not used for a member of an // explicitly specialized class template
+void A<int>::f(int) { /* ... */ }
+ template<> struct A<char>::B {
+ void f();
+};
+// template<> also not used when defining a member of // an explicitly specialized member class
+void A<char>::B::f() { /* ... */ }
+ template<> template<class U> struct A<char>::C {
+ void f();
+};
+
+template<>
+template<class U> void A<char>::C<U>::f() { /* ... */ }
+ template<> struct A<short>::B {
+ void f();
+};
+template<> void A<short>::B::f() { /* ... */ } // expected-error{{no function template matches function template specialization 'f'}}
+ template<> template<class U> struct A<short>::C {
+ void f();
+};
+template<class U> void A<short>::C<U>::f() { /* ... */ } // expected-error{{template parameter list matching the non-templated nested type 'A<short>' should be empty ('template<>')}}
diff --git a/test/CXX/temp/temp.spec/temp.explicit/p2.cpp b/test/CXX/temp/temp.spec/temp.explicit/p2.cpp
index 70d338b..822f881 100644
--- a/test/CXX/temp/temp.spec/temp.explicit/p2.cpp
+++ b/test/CXX/temp/temp.spec/temp.explicit/p2.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -verify %s
+// RUN: %clang_cc1 -fsyntax-only -verify -pedantic %s
// Example from the standard
template<class T> class Array { void mf() { } };
@@ -35,7 +35,7 @@ namespace N {
};
template<typename T>
- void f1(T) {}; // expected-note{{explicit instantiation refers here}}
+ void f1(T) {} // expected-note{{explicit instantiation refers here}}
}
using namespace N;
diff --git a/test/CXX/temp/temp.type/p1-0x.cpp b/test/CXX/temp/temp.type/p1-0x.cpp
new file mode 100644
index 0000000..c22af22
--- /dev/null
+++ b/test/CXX/temp/temp.type/p1-0x.cpp
@@ -0,0 +1,23 @@
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++0x %s
+
+namespace Old {
+ template<template<class> class TT> struct X { };
+ template<class> struct Y { };
+ template<class T> using Z = Y<T>;
+ X<Y> y;
+ X<Z> z;
+
+ using SameType = decltype(y); // expected-note {{here}}
+ using SameType = decltype(z); // expected-error {{different types}}
+}
+
+namespace New {
+ template<class T> struct X { };
+ template<class> struct Y { };
+ template<class T> using Z = Y<T>;
+ X<Y<int>> y;
+ X<Z<int>> z;
+
+ using SameType = decltype(y);
+ using SameType = decltype(z); // ok
+}
diff --git a/test/CodeGen/2009-10-20-GlobalDebug.c b/test/CodeGen/2009-10-20-GlobalDebug.c
index 3c46bea..42f020e 100644
--- a/test/CodeGen/2009-10-20-GlobalDebug.c
+++ b/test/CodeGen/2009-10-20-GlobalDebug.c
@@ -1,3 +1,4 @@
+// REQUIRES: x86-registered-target
// RUN: %clang -ccc-host-triple i386-apple-darwin10 -S -g -dA %s -o - | FileCheck %s
int global;
// CHECK: ascii "localstatic" ## DW_AT_name
diff --git a/test/CodeGen/altivec.c b/test/CodeGen/altivec.c
index ec1efd9..c3b1f42 100644
--- a/test/CodeGen/altivec.c
+++ b/test/CodeGen/altivec.c
@@ -23,7 +23,7 @@ void test2()
// Check pre/post increment/decrement
void test3() {
vector int vi;
- vi++; // CHECK: add nsw <4 x i32> {{.*}} <i32 1, i32 1, i32 1, i32 1>
+ vi++; // CHECK: add <4 x i32> {{.*}} <i32 1, i32 1, i32 1, i32 1>
vector unsigned int vui;
--vui; // CHECK: add <4 x i32> {{.*}} <i32 -1, i32 -1, i32 -1, i32 -1>
vector float vf;
diff --git a/test/CodeGen/arm-asm.c b/test/CodeGen/arm-asm.c
new file mode 100644
index 0000000..9b1082a
--- /dev/null
+++ b/test/CodeGen/arm-asm.c
@@ -0,0 +1,7 @@
+// RUN: %clang_cc1 -triple thumb %s -emit-llvm -o - | FileCheck %s
+int t1() {
+ static float k = 1.0f;
+ // CHECK: flds s15
+ __asm__ volatile ("flds s15, %[k] \n" :: [k] "Uv" (k) : "s15");
+ return 0;
+}
diff --git a/test/CodeGen/asm-errors.c b/test/CodeGen/asm-errors.c
index c5b36c7..cd4d1ff 100644
--- a/test/CodeGen/asm-errors.c
+++ b/test/CodeGen/asm-errors.c
@@ -1,3 +1,4 @@
+// REQUIRES: x86-registered-target
// RUN: not %clang_cc1 -triple i386-apple-darwin10 -emit-obj %s -o /dev/null > %t 2>&1
// RUN: FileCheck %s < %t
diff --git a/test/CodeGen/asm-label.c b/test/CodeGen/asm-label.c
new file mode 100644
index 0000000..7be2ad3
--- /dev/null
+++ b/test/CodeGen/asm-label.c
@@ -0,0 +1,12 @@
+// RUN: %clang_cc1 -triple=i686-pc-linux-gnu -emit-llvm %s -o - | FileCheck %s --check-prefix=LINUX
+// RUN: %clang_cc1 -triple=i686-apple-darwin9 -emit-llvm %s -o - | FileCheck %s --check-prefix=DARWIN
+
+char *strerror(int) asm("alias");
+
+void test(void)
+{
+ strerror(-1);
+}
+
+// LINUX: declare i8* @alias(i32)
+// DARWIN: declare i8* @"\01alias"(i32)
diff --git a/test/CodeGen/available-externally-suppress.c b/test/CodeGen/available-externally-suppress.c
index 747d3cd..46b6e74 100644
--- a/test/CodeGen/available-externally-suppress.c
+++ b/test/CodeGen/available-externally-suppress.c
@@ -11,17 +11,17 @@ void test() {
f0(17);
}
-inline int __attribute__((always_inline)) f1(int x) {
+inline int __attribute__((always_inline)) f1(int x) {
int blarg = 0;
for (int i = 0; i < x; ++i)
blarg = blarg + x * i;
- return blarg;
+ return blarg;
}
// CHECK: @test1
-int test1(int x) {
+int test1(int x) {
// CHECK: br i1
- // CHECK-NOT: call
+ // CHECK-NOT: call {{.*}} @f1
// CHECK: ret i32
- return f1(x);
+ return f1(x);
}
diff --git a/test/CodeGen/avx-cmp-builtins.c b/test/CodeGen/avx-cmp-builtins.c
new file mode 100644
index 0000000..1ac1c31
--- /dev/null
+++ b/test/CodeGen/avx-cmp-builtins.c
@@ -0,0 +1,46 @@
+// RUN: %clang_cc1 %s -O3 -triple=x86_64-apple-darwin -target-feature +avx -emit-llvm -o - | FileCheck %s
+
+// Don't include mm_malloc.h, it's system specific.
+#define __MM_MALLOC_H
+
+#include <immintrin.h>
+
+//
+// Test LLVM IR codegen of cmpXY instructions
+//
+
+__m128d test_cmp_pd(__m128d a, __m128d b) {
+ // Expects that the third argument in LLVM IR is immediate expression
+ // CHECK: @llvm.x86.sse2.cmp.pd({{.*}}, i8 13)
+ return _mm_cmp_pd(a, b, _CMP_GE_OS);
+}
+
+__m128d test_cmp_ps(__m128 a, __m128 b) {
+ // Expects that the third argument in LLVM IR is immediate expression
+ // CHECK: @llvm.x86.sse.cmp.ps({{.*}}, i8 13)
+ return _mm_cmp_ps(a, b, _CMP_GE_OS);
+}
+
+__m256d test_cmp_pd256(__m256d a, __m256d b) {
+ // Expects that the third argument in LLVM IR is immediate expression
+ // CHECK: @llvm.x86.avx.cmp.pd.256({{.*}}, i8 13)
+ return _mm256_cmp_pd(a, b, _CMP_GE_OS);
+}
+
+__m256d test_cmp_ps256(__m256 a, __m256 b) {
+ // Expects that the third argument in LLVM IR is immediate expression
+ // CHECK: @llvm.x86.avx.cmp.ps.256({{.*}}, i8 13)
+ return _mm256_cmp_ps(a, b, _CMP_GE_OS);
+}
+
+__m128d test_cmp_sd(__m128d a, __m128d b) {
+ // Expects that the third argument in LLVM IR is immediate expression
+ // CHECK: @llvm.x86.sse2.cmp.sd({{.*}}, i8 13)
+ return _mm_cmp_sd(a, b, _CMP_GE_OS);
+}
+
+__m128d test_cmp_ss(__m128 a, __m128 b) {
+ // Expects that the third argument in LLVM IR is immediate expression
+ // CHECK: @llvm.x86.sse.cmp.ss({{.*}}, i8 13)
+ return _mm_cmp_ss(a, b, _CMP_GE_OS);
+}
diff --git a/test/CodeGen/builtins-ppc-altivec.c b/test/CodeGen/builtins-ppc-altivec.c
index 586f113..b12ff01 100644
--- a/test/CodeGen/builtins-ppc-altivec.c
+++ b/test/CodeGen/builtins-ppc-altivec.c
@@ -44,13 +44,13 @@ int res_f;
void test1() {
/* vec_abs */
- vsc = vec_abs(vsc); // CHECK: sub nsw <16 x i8> zeroinitializer
+ vsc = vec_abs(vsc); // CHECK: sub <16 x i8> zeroinitializer
// CHECK: @llvm.ppc.altivec.vmaxsb
- vs = vec_abs(vs); // CHECK: sub nsw <8 x i16> zeroinitializer
+ vs = vec_abs(vs); // CHECK: sub <8 x i16> zeroinitializer
// CHECK: @llvm.ppc.altivec.vmaxsh
- vi = vec_abs(vi); // CHECK: sub nsw <4 x i32> zeroinitializer
+ vi = vec_abs(vi); // CHECK: sub <4 x i32> zeroinitializer
// CHECK: @llvm.ppc.altivec.vmaxsw
vf = vec_abs(vf); // CHECK: and <4 x i32>
@@ -66,40 +66,40 @@ void test1() {
// CHECK: @llvm.ppc.altivec.vmaxsw
/* vec_add */
- res_vsc = vec_add(vsc, vsc); // CHECK: add nsw <16 x i8>
- res_vsc = vec_add(vbc, vsc); // CHECK: add nsw <16 x i8>
- res_vsc = vec_add(vsc, vbc); // CHECK: add nsw <16 x i8>
+ res_vsc = vec_add(vsc, vsc); // CHECK: add <16 x i8>
+ res_vsc = vec_add(vbc, vsc); // CHECK: add <16 x i8>
+ res_vsc = vec_add(vsc, vbc); // CHECK: add <16 x i8>
res_vuc = vec_add(vuc, vuc); // CHECK: add <16 x i8>
res_vuc = vec_add(vbc, vuc); // CHECK: add <16 x i8>
res_vuc = vec_add(vuc, vbc); // CHECK: add <16 x i8>
- res_vs = vec_add(vs, vs); // CHECK: add nsw <8 x i16>
- res_vs = vec_add(vbs, vs); // CHECK: add nsw <8 x i16>
- res_vs = vec_add(vs, vbs); // CHECK: add nsw <8 x i16>
+ res_vs = vec_add(vs, vs); // CHECK: add <8 x i16>
+ res_vs = vec_add(vbs, vs); // CHECK: add <8 x i16>
+ res_vs = vec_add(vs, vbs); // CHECK: add <8 x i16>
res_vus = vec_add(vus, vus); // CHECK: add <8 x i16>
res_vus = vec_add(vbs, vus); // CHECK: add <8 x i16>
res_vus = vec_add(vus, vbs); // CHECK: add <8 x i16>
- res_vi = vec_add(vi, vi); // CHECK: add nsw <4 x i32>
- res_vi = vec_add(vbi, vi); // CHECK: add nsw <4 x i32>
- res_vi = vec_add(vi, vbi); // CHECK: add nsw <4 x i32>
+ res_vi = vec_add(vi, vi); // CHECK: add <4 x i32>
+ res_vi = vec_add(vbi, vi); // CHECK: add <4 x i32>
+ res_vi = vec_add(vi, vbi); // CHECK: add <4 x i32>
res_vui = vec_add(vui, vui); // CHECK: add <4 x i32>
res_vui = vec_add(vbi, vui); // CHECK: add <4 x i32>
res_vui = vec_add(vui, vbi); // CHECK: add <4 x i32>
res_vf = vec_add(vf, vf); // CHECK: fadd <4 x float>
- res_vsc = vec_vaddubm(vsc, vsc); // CHECK: add nsw <16 x i8>
- res_vsc = vec_vaddubm(vbc, vsc); // CHECK: add nsw <16 x i8>
- res_vsc = vec_vaddubm(vsc, vbc); // CHECK: add nsw <16 x i8>
+ res_vsc = vec_vaddubm(vsc, vsc); // CHECK: add <16 x i8>
+ res_vsc = vec_vaddubm(vbc, vsc); // CHECK: add <16 x i8>
+ res_vsc = vec_vaddubm(vsc, vbc); // CHECK: add <16 x i8>
res_vuc = vec_vaddubm(vuc, vuc); // CHECK: add <16 x i8>
res_vuc = vec_vaddubm(vbc, vuc); // CHECK: add <16 x i8>
res_vuc = vec_vaddubm(vuc, vbc); // CHECK: add <16 x i8>
- res_vs = vec_vadduhm(vs, vs); // CHECK: add nsw <8 x i16>
- res_vs = vec_vadduhm(vbs, vs); // CHECK: add nsw <8 x i16>
- res_vs = vec_vadduhm(vs, vbs); // CHECK: add nsw <8 x i16>
+ res_vs = vec_vadduhm(vs, vs); // CHECK: add <8 x i16>
+ res_vs = vec_vadduhm(vbs, vs); // CHECK: add <8 x i16>
+ res_vs = vec_vadduhm(vs, vbs); // CHECK: add <8 x i16>
res_vus = vec_vadduhm(vus, vus); // CHECK: add <8 x i16>
res_vus = vec_vadduhm(vbs, vus); // CHECK: add <8 x i16>
res_vus = vec_vadduhm(vus, vbs); // CHECK: add <8 x i16>
- res_vi = vec_vadduwm(vi, vi); // CHECK: add nsw <4 x i32>
- res_vi = vec_vadduwm(vbi, vi); // CHECK: add nsw <4 x i32>
- res_vi = vec_vadduwm(vi, vbi); // CHECK: add nsw <4 x i32>
+ res_vi = vec_vadduwm(vi, vi); // CHECK: add <4 x i32>
+ res_vi = vec_vadduwm(vbi, vi); // CHECK: add <4 x i32>
+ res_vi = vec_vadduwm(vi, vbi); // CHECK: add <4 x i32>
res_vui = vec_vadduwm(vui, vui); // CHECK: add <4 x i32>
res_vui = vec_vadduwm(vbi, vui); // CHECK: add <4 x i32>
res_vui = vec_vadduwm(vui, vbi); // CHECK: add <4 x i32>
@@ -689,14 +689,14 @@ void test6() {
res_vus = vec_mladd(vus, vus, vus); // CHECK: mul <8 x i16>
// CHECK: add <8 x i16>
- res_vs = vec_mladd(vus, vs, vs); // CHECK: mul nsw <8 x i16>
- // CHECK: add nsw <8 x i16>
+ res_vs = vec_mladd(vus, vs, vs); // CHECK: mul <8 x i16>
+ // CHECK: add <8 x i16>
- res_vs = vec_mladd(vs, vus, vus); // CHECK: mul nsw <8 x i16>
- // CHECK: add nsw <8 x i16>
+ res_vs = vec_mladd(vs, vus, vus); // CHECK: mul <8 x i16>
+ // CHECK: add <8 x i16>
- res_vs = vec_mladd(vs, vs, vs); // CHECK: mul nsw <8 x i16>
- // CHECK: add nsw <8 x i16>
+ res_vs = vec_mladd(vs, vs, vs); // CHECK: mul <8 x i16>
+ // CHECK: add <8 x i16>
/* vec_mradds */
res_vs = vec_mradds(vs, vs, vs); // CHECK: @llvm.ppc.altivec.vmhraddshs
@@ -1592,40 +1592,40 @@ void test6() {
vec_stvxl(vf, 0, &param_f); // CHECK: @llvm.ppc.altivec.stvxl
/* vec_sub */
- res_vsc = vec_sub(vsc, vsc); // CHECK: sub nsw <16 x i8>
- res_vsc = vec_sub(vbc, vsc); // CHECK: sub nsw <16 x i8>
- res_vsc = vec_sub(vsc, vbc); // CHECK: sub nsw <16 x i8>
+ res_vsc = vec_sub(vsc, vsc); // CHECK: sub <16 x i8>
+ res_vsc = vec_sub(vbc, vsc); // CHECK: sub <16 x i8>
+ res_vsc = vec_sub(vsc, vbc); // CHECK: sub <16 x i8>
res_vuc = vec_sub(vuc, vuc); // CHECK: sub <16 x i8>
res_vuc = vec_sub(vbc, vuc); // CHECK: sub <16 x i8>
res_vuc = vec_sub(vuc, vbc); // CHECK: sub <16 x i8>
- res_vs = vec_sub(vs, vs); // CHECK: sub nsw <8 x i16>
- res_vs = vec_sub(vbs, vs); // CHECK: sub nsw <8 x i16>
- res_vs = vec_sub(vs, vbs); // CHECK: sub nsw <8 x i16>
+ res_vs = vec_sub(vs, vs); // CHECK: sub <8 x i16>
+ res_vs = vec_sub(vbs, vs); // CHECK: sub <8 x i16>
+ res_vs = vec_sub(vs, vbs); // CHECK: sub <8 x i16>
res_vus = vec_sub(vus, vus); // CHECK: sub <8 x i16>
res_vus = vec_sub(vbs, vus); // CHECK: sub <8 x i16>
res_vus = vec_sub(vus, vbs); // CHECK: sub <8 x i16>
- res_vi = vec_sub(vi, vi); // CHECK: sub nsw <4 x i32>
- res_vi = vec_sub(vbi, vi); // CHECK: sub nsw <4 x i32>
- res_vi = vec_sub(vi, vbi); // CHECK: sub nsw <4 x i32>
+ res_vi = vec_sub(vi, vi); // CHECK: sub <4 x i32>
+ res_vi = vec_sub(vbi, vi); // CHECK: sub <4 x i32>
+ res_vi = vec_sub(vi, vbi); // CHECK: sub <4 x i32>
res_vui = vec_sub(vui, vui); // CHECK: sub <4 x i32>
res_vui = vec_sub(vbi, vui); // CHECK: sub <4 x i32>
res_vui = vec_sub(vui, vbi); // CHECK: sub <4 x i32>
res_vf = vec_sub(vf, vf); // CHECK: fsub <4 x float>
- res_vsc = vec_vsububm(vsc, vsc); // CHECK: sub nsw <16 x i8>
- res_vsc = vec_vsububm(vbc, vsc); // CHECK: sub nsw <16 x i8>
- res_vsc = vec_vsububm(vsc, vbc); // CHECK: sub nsw <16 x i8>
+ res_vsc = vec_vsububm(vsc, vsc); // CHECK: sub <16 x i8>
+ res_vsc = vec_vsububm(vbc, vsc); // CHECK: sub <16 x i8>
+ res_vsc = vec_vsububm(vsc, vbc); // CHECK: sub <16 x i8>
res_vuc = vec_vsububm(vuc, vuc); // CHECK: sub <16 x i8>
res_vuc = vec_vsububm(vbc, vuc); // CHECK: sub <16 x i8>
res_vuc = vec_vsububm(vuc, vbc); // CHECK: sub <16 x i8>
- res_vs = vec_vsubuhm(vs, vs); // CHECK: sub nsw <8 x i16>
+ res_vs = vec_vsubuhm(vs, vs); // CHECK: sub <8 x i16>
res_vs = vec_vsubuhm(vbs, vus); // CHECK: sub <8 x i16>
res_vs = vec_vsubuhm(vus, vbs); // CHECK: sub <8 x i16>
res_vus = vec_vsubuhm(vus, vus); // CHECK: sub <8 x i16>
res_vus = vec_vsubuhm(vbs, vus); // CHECK: sub <8 x i16>
res_vus = vec_vsubuhm(vus, vbs); // CHECK: sub <8 x i16>
- res_vi = vec_vsubuwm(vi, vi); // CHECK: sub nsw <4 x i32>
- res_vi = vec_vsubuwm(vbi, vi); // CHECK: sub nsw <4 x i32>
- res_vi = vec_vsubuwm(vi, vbi); // CHECK: sub nsw <4 x i32>
+ res_vi = vec_vsubuwm(vi, vi); // CHECK: sub <4 x i32>
+ res_vi = vec_vsubuwm(vbi, vi); // CHECK: sub <4 x i32>
+ res_vi = vec_vsubuwm(vi, vbi); // CHECK: sub <4 x i32>
res_vui = vec_vsubuwm(vui, vui); // CHECK: sub <4 x i32>
res_vui = vec_vsubuwm(vbi, vui); // CHECK: sub <4 x i32>
res_vui = vec_vsubuwm(vui, vbi); // CHECK: sub <4 x i32>
diff --git a/test/CodeGen/builtins-x86.c b/test/CodeGen/builtins-x86.c
index bb63048..728ade3 100644
--- a/test/CodeGen/builtins-x86.c
+++ b/test/CodeGen/builtins-x86.c
@@ -317,7 +317,6 @@ void f0() {
(void) __builtin_ia32_clflush(tmp_vCp);
(void) __builtin_ia32_lfence();
(void) __builtin_ia32_mfence();
- tmp_V16c = __builtin_ia32_loaddqu(tmp_cCp);
(void) __builtin_ia32_storedqu(tmp_cp, tmp_V16c);
tmp_V4s = __builtin_ia32_psllwi(tmp_V4s, tmp_i);
tmp_V2i = __builtin_ia32_pslldi(tmp_V2i, tmp_i);
diff --git a/test/CodeGen/builtinshufflevector.c b/test/CodeGen/builtinshufflevector.c
index f365844..5c647df 100644
--- a/test/CodeGen/builtinshufflevector.c
+++ b/test/CodeGen/builtinshufflevector.c
@@ -1,5 +1,6 @@
// RUN: %clang_cc1 -emit-llvm < %s | grep 'shufflevector' | count 1
+// RUN: %clang_cc1 -emit-llvm -ftrapv < %s | grep 'shufflevector' | count 1
typedef int v4si __attribute__ ((vector_size (16)));
-v4si a(v4si x, v4si y) {return __builtin_shufflevector(x, y, 3, 2, 5, 7);}
+v4si a(v4si x, v4si y) {return __builtin_shufflevector(x, y, 3, 2, 5, (2*3)+1);}
diff --git a/test/CodeGen/byval-memcpy-elim.c b/test/CodeGen/byval-memcpy-elim.c
new file mode 100644
index 0000000..8aa08fb
--- /dev/null
+++ b/test/CodeGen/byval-memcpy-elim.c
@@ -0,0 +1,20 @@
+// RUN: %clang_cc1 -emit-llvm -triple x86_64-apple-darwin10 < %s | FileCheck %s
+
+struct Test1S {
+ long NumDecls;
+ long X;
+ long Y;
+};
+struct Test2S {
+ long NumDecls;
+ long X;
+};
+
+// Make sure we don't generate extra memcpy for lvalues
+void test1a(struct Test1S, struct Test2S);
+// CHECK: define void @test1(
+// CHECK-NOT: memcpy
+// CHECK: call void @test1a
+void test1(struct Test1S *A, struct Test2S *B) {
+ test1a(*A, *B);
+}
diff --git a/test/CodeGen/debug-info-crash.c b/test/CodeGen/debug-info-crash.c
index 8d6a360..f04548b 100644
--- a/test/CodeGen/debug-info-crash.c
+++ b/test/CodeGen/debug-info-crash.c
@@ -1,3 +1,4 @@
+// REQUIRES: x86-registered-target
// RUN: %clang_cc1 -triple i386-apple-darwin10 -fblocks -g -S %s -o -
// rdar://7590323
diff --git a/test/CodeGen/debug-info.c b/test/CodeGen/debug-info.c
index a84d0b2..876c6c2 100644
--- a/test/CodeGen/debug-info.c
+++ b/test/CodeGen/debug-info.c
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -o %t -emit-llvm -g %s
+// RUN: %clang_cc1 -triple x86_64-unk-unk -o %t -emit-llvm -g %s
// RUN: FileCheck --input-file=%t %s
// PR3023
@@ -47,3 +47,10 @@ struct foo2 foo2;
typedef int barfoo;
barfoo foo() {
}
+
+// CHECK: __uint128_t
+__uint128_t foo128 ()
+{
+ __uint128_t int128 = 44;
+ return int128;
+}
diff --git a/test/CodeGen/decl.c b/test/CodeGen/decl.c
index 7a9971e..29520d7 100644
--- a/test/CodeGen/decl.c
+++ b/test/CodeGen/decl.c
@@ -1,11 +1,11 @@
// RUN: %clang_cc1 -w -emit-llvm < %s | FileCheck %s
// CHECK: @test1.x = internal constant [12 x i32] [i32 1
-// CHECK: @test2.x = internal constant [13 x i32] [i32 1,
+// CHECK: @test2.x = internal unnamed_addr constant [13 x i32] [i32 1,
// CHECK: @test5w = global %0 { i32 2, [4 x i8] undef }
// CHECK: @test5y = global %union.test5u { double 7.300000e+0{{[0]*}}1 }
-// CHECK: @test6.x = internal constant %struct.SelectDest { i8 1, i8 2, i32 3, i32 0 }
+// CHECK: @test6.x = internal unnamed_addr constant %struct.SelectDest { i8 1, i8 2, i32 3, i32 0 }
// CHECK: @test7 = global [2 x %struct.test7s] [%struct.test7s { i32 1, i32 2 }, %struct.test7s { i32 4, i32 0 }]
diff --git a/test/CodeGen/ext-vector.c b/test/CodeGen/ext-vector.c
index 1abd9f2..a222f94 100644
--- a/test/CodeGen/ext-vector.c
+++ b/test/CodeGen/ext-vector.c
@@ -131,9 +131,9 @@ void test7(int4 *ap, int4 *bp, int c) {
int4 a = *ap;
int4 b = *bp;
- // CHECK: add nsw <4 x i32>
- // CHECK: sub nsw <4 x i32>
- // CHECK: mul nsw <4 x i32>
+ // CHECK: add <4 x i32>
+ // CHECK: sub <4 x i32>
+ // CHECK: mul <4 x i32>
// CHECK: sdiv <4 x i32>
// CHECK: srem <4 x i32>
a = a + b;
@@ -142,9 +142,9 @@ void test7(int4 *ap, int4 *bp, int c) {
a = a / b;
a = a % b;
- // CHECK: add nsw <4 x i32>
- // CHECK: sub nsw <4 x i32>
- // CHECK: mul nsw <4 x i32>
+ // CHECK: add <4 x i32>
+ // CHECK: sub <4 x i32>
+ // CHECK: mul <4 x i32>
// CHECK: sdiv <4 x i32>
// CHECK: srem <4 x i32>
a = a + c;
@@ -153,9 +153,9 @@ void test7(int4 *ap, int4 *bp, int c) {
a = a / c;
a = a % c;
- // CHECK: add nsw <4 x i32>
- // CHECK: sub nsw <4 x i32>
- // CHECK: mul nsw <4 x i32>
+ // CHECK: add <4 x i32>
+ // CHECK: sub <4 x i32>
+ // CHECK: mul <4 x i32>
// CHECK: sdiv <4 x i32>
// CHECK: srem <4 x i32>
a += b;
@@ -164,9 +164,9 @@ void test7(int4 *ap, int4 *bp, int c) {
a /= b;
a %= b;
- // CHECK: add nsw <4 x i32>
- // CHECK: sub nsw <4 x i32>
- // CHECK: mul nsw <4 x i32>
+ // CHECK: add <4 x i32>
+ // CHECK: sub <4 x i32>
+ // CHECK: mul <4 x i32>
// CHECK: sdiv <4 x i32>
// CHECK: srem <4 x i32>
a += c;
@@ -220,7 +220,7 @@ int test9(int4 V) {
}
// CHECK: @test10
-// CHECK: add nsw <4 x i32>
+// CHECK: add <4 x i32>
// CHECK: extractelement <4 x i32>
int test10(int4 V) {
return (V+V).x;
diff --git a/test/CodeGen/extern-inline.c b/test/CodeGen/extern-inline.c
index 60f6d03..e3df996 100644
--- a/test/CodeGen/extern-inline.c
+++ b/test/CodeGen/extern-inline.c
@@ -1,4 +1,5 @@
// RUN: %clang -S -emit-llvm -std=gnu89 -o - %s | FileCheck %s
+// RUN: %clang -S -emit-llvm -fgnu89-inline -o - %s | FileCheck %s
// PR5253
// If an extern inline function is redefined, functions should call the
diff --git a/test/CodeGen/frame-pointer-elim.c b/test/CodeGen/frame-pointer-elim.c
index e9dc22b..4e8e946 100644
--- a/test/CodeGen/frame-pointer-elim.c
+++ b/test/CodeGen/frame-pointer-elim.c
@@ -1,3 +1,5 @@
+// REQUIRES: x86-registered-target
+
// RUN: %clang -ccc-host-triple i386-apple-darwin -S -o - %s | \
// RUN: FileCheck --check-prefix=DARWIN %s
// DARWIN: f0:
diff --git a/test/CodeGen/inline.c b/test/CodeGen/inline.c
index a6b4b3e..96f9c5c 100644
--- a/test/CodeGen/inline.c
+++ b/test/CodeGen/inline.c
@@ -29,7 +29,7 @@
// RUN: grep "define available_externally i32 @test5" %t
// RUN: echo "\nC++ tests:"
-// RUN: %clang %s -O1 -emit-llvm -S -o %t -std=c++98
+// RUN: %clang -x c++ %s -O1 -emit-llvm -S -o %t -std=c++98
// RUN: grep "define linkonce_odr i32 @_Z2eiv()" %t
// RUN: grep "define linkonce_odr i32 @_Z3foov()" %t
// RUN: grep "define i32 @_Z3barv()" %t
diff --git a/test/CodeGen/mmx-builtins.c b/test/CodeGen/mmx-builtins.c
index 7934e77..b142684 100644
--- a/test/CodeGen/mmx-builtins.c
+++ b/test/CodeGen/mmx-builtins.c
@@ -1,3 +1,4 @@
+// REQUIRES: x86-64-registered-target
// RUN: %clang_cc1 %s -O3 -triple=x86_64-apple-darwin -target-feature +ssse3 -S -o - | FileCheck %s
// FIXME: Disable inclusion of mm_malloc.h, our current implementation is broken
diff --git a/test/CodeGen/ms_struct-bitfield-1.c b/test/CodeGen/ms_struct-bitfield-1.c
new file mode 100644
index 0000000..0b15a24
--- /dev/null
+++ b/test/CodeGen/ms_struct-bitfield-1.c
@@ -0,0 +1,91 @@
+// RUN: %clang_cc1 -emit-llvm-only -triple x86_64-apple-darwin9 %s
+// rdar://8823265
+
+#define ATTR __attribute__((__ms_struct__))
+
+struct {
+ unsigned int bf_1 : 12;
+ unsigned int : 0;
+ unsigned int bf_2 : 12;
+} ATTR t1;
+static int a1[(sizeof(t1) == 8) -1];
+
+struct
+{
+ char foo : 4;
+ short : 0;
+ char bar;
+} ATTR t2;
+static int a2[(sizeof(t2) == 4) -1];
+
+#pragma ms_struct on
+struct
+{
+ char foo : 4;
+ short : 0;
+ char bar;
+} t3;
+#pragma ms_struct off
+static int a3[(sizeof(t3) == 4) -1];
+
+struct
+{
+ char foo : 6;
+ long : 0;
+} ATTR t4;
+static int a4[(sizeof(t4) == 8) -1];
+
+struct
+{
+ char foo : 4;
+ short : 0;
+ char bar : 8;
+} ATTR t5;
+static int a5[(sizeof(t5) == 4) -1];
+
+struct
+{
+ char foo : 4;
+ short : 0;
+ long :0;
+ char bar;
+} ATTR t6;
+static int a6[(sizeof(t6) == 4) -1];
+
+struct
+{
+ char foo : 4;
+ long :0;
+ short : 0;
+ char bar;
+} ATTR t7;
+static int a7[(sizeof(t7) == 16) -1];
+
+struct
+{
+ char foo : 4;
+ short : 0;
+ long :0;
+ char bar:7;
+} ATTR t8;
+static int a8[(sizeof(t8) == 4) -1];
+
+struct
+{
+ char foo : 4;
+ long :0;
+ short : 0;
+ char bar: 8;
+} ATTR t9;
+static int a9[(sizeof(t9) == 16) -1];
+
+struct
+{
+ char foo : 4;
+ char : 0;
+ short : 0;
+ int : 0;
+ long :0;
+ char bar;
+} ATTR t10;
+static int a10[(sizeof(t10) == 2) -1];
diff --git a/test/CodeGen/ms_struct-bitfield-2.c b/test/CodeGen/ms_struct-bitfield-2.c
new file mode 100644
index 0000000..36e0172
--- /dev/null
+++ b/test/CodeGen/ms_struct-bitfield-2.c
@@ -0,0 +1,135 @@
+// RUN: %clang_cc1 -emit-llvm-only -triple x86_64-apple-darwin9 %s
+// rdar://8823265
+
+#define ATTR __attribute__((__ms_struct__))
+
+#define size_struct_0 1
+#define size_struct_1 4
+#define size_struct_2 24
+#define size_struct_3 8
+#define size_struct_4 32
+#define size_struct_5 12
+#define size_struct_6 40
+#define size_struct_7 8
+#define size_struct_8 20
+#define size_struct_9 32
+
+struct _struct_0
+{
+ char member_0;
+} ATTR;
+typedef struct _struct_0 struct_0;
+
+struct _struct_1
+{
+ char member_0;
+ short member_1:13;
+} ATTR;
+typedef struct _struct_1 struct_1;
+
+struct _struct_2
+{
+ double member_0;
+ unsigned char member_1:8;
+ int member_2:32;
+ unsigned char member_3:5;
+ short member_4:14;
+ short member_5:13;
+ unsigned char:0;
+} ATTR;
+typedef struct _struct_2 struct_2;
+
+struct _struct_3
+{
+ unsigned int member_0:26;
+ unsigned char member_1:2;
+
+} ATTR;
+typedef struct _struct_3 struct_3;
+
+struct _struct_4
+{
+ unsigned char member_0:7;
+ double member_1;
+ double member_2;
+ short member_3:5;
+ char member_4:2;
+
+} ATTR;
+typedef struct _struct_4 struct_4;
+
+struct _struct_5
+{
+ unsigned short member_0:12;
+ int member_1:1;
+ unsigned short member_2:6;
+
+} ATTR;
+typedef struct _struct_5 struct_5;
+
+struct _struct_6
+{
+ unsigned char member_0:7;
+ unsigned int member_1:25;
+ char member_2:1;
+ double member_3;
+ short member_4:9;
+ double member_5;
+
+} ATTR;
+typedef struct _struct_6 struct_6;
+
+struct _struct_7
+{
+ double member_0;
+
+} ATTR;
+typedef struct _struct_7 struct_7;
+
+struct _struct_8
+{
+ unsigned char member_0:7;
+ int member_1:11;
+ int member_2:5;
+ int:0;
+ char member_4:8;
+ unsigned short member_5:4;
+ unsigned char member_6:3;
+ int member_7:23;
+
+} ATTR;
+typedef struct _struct_8 struct_8;
+
+struct _struct_9
+{
+ double member_0;
+ unsigned int member_1:6;
+ int member_2:17;
+ double member_3;
+ unsigned int member_4:22;
+
+} ATTR;
+typedef struct _struct_9 struct_9;
+
+struct_0 test_struct_0 = { 123 };
+struct_1 test_struct_1 = { 82, 1081 };
+struct_2 test_struct_2 = { 20.0, 31, 407760, 1, 14916, 6712 };
+struct_3 test_struct_3 = { 64616999, 1 };
+struct_4 test_struct_4 = { 61, 20.0, 20.0, 12, 0 };
+struct_5 test_struct_5 = { 909, 1, 57 };
+struct_6 test_struct_6 = { 12, 21355796, 0, 20.0, 467, 20.0 };
+struct_7 test_struct_7 = { 20.0 };
+struct_8 test_struct_8 = { 126, 1821, 22, 125, 6, 0, 2432638 };
+struct_9 test_struct_9 = { 20.0, 3, 23957, 20.0, 1001631 };
+
+
+static int a0[(sizeof (struct_0) == size_struct_0) -1];
+static int a1[(sizeof (struct_1) == size_struct_1) -1];
+static int a2[(sizeof (struct_2) == size_struct_2) -1];
+static int a3[(sizeof (struct_3) == size_struct_3) -1];
+static int a4[(sizeof (struct_4) == size_struct_4) -1];
+static int a5[(sizeof (struct_5) == size_struct_5) -1];
+static int a6[(sizeof (struct_6) == size_struct_6) -1];
+static int a7[(sizeof (struct_7) == size_struct_7) -1];
+static int a8[(sizeof (struct_8) == size_struct_8) -1];
+static int a9[(sizeof (struct_9) == size_struct_9) -1];
diff --git a/test/CodeGen/ms_struct-bitfield-3.c b/test/CodeGen/ms_struct-bitfield-3.c
new file mode 100644
index 0000000..0eba435
--- /dev/null
+++ b/test/CodeGen/ms_struct-bitfield-3.c
@@ -0,0 +1,49 @@
+// RUN: %clang_cc1 -emit-llvm-only -triple i386-apple-darwin9 %s
+// rdar://8823265
+
+#define ATTR __attribute__((__ms_struct__))
+
+struct _struct_0
+{
+ int member_0 : 25 ;
+ short member_1 : 6 ;
+ char member_2 : 2 ;
+ unsigned short member_3 : 1 ;
+ unsigned char member_4 : 7 ;
+ short member_5 : 16 ;
+ int : 0 ;
+ char member_7 ;
+
+} ATTR;
+
+typedef struct _struct_0 struct_0;
+
+#define size_struct_0 20
+
+struct_0 test_struct_0 = { 18557917, 17, 3, 0, 80, 6487, 93 };
+static int a[(size_struct_0 == sizeof (struct_0)) -1];
+
+struct _struct_1 {
+ int d;
+ unsigned char a;
+ unsigned short b:7;
+ char c;
+} ATTR;
+
+typedef struct _struct_1 struct_1;
+
+#define size_struct_1 12
+
+struct_1 test_struct_1 = { 18557917, 'a', 3, 'b' };
+
+static int a1[(size_struct_1 == sizeof (struct_1)) -1];
+
+struct ten {
+ long long a:3;
+ long long b:3;
+ char c;
+} __attribute__ ((ms_struct));
+
+#define size_struct_2 16
+
+static int a2[(size_struct_2 == sizeof (struct ten)) -1];
diff --git a/test/CodeGen/ms_struct-pack.c b/test/CodeGen/ms_struct-pack.c
new file mode 100644
index 0000000..da94f54
--- /dev/null
+++ b/test/CodeGen/ms_struct-pack.c
@@ -0,0 +1,125 @@
+// RUN: %clang_cc1 -emit-llvm-only -triple i386-apple-darwin9 %s
+// rdar://8823265
+
+#pragma pack(1)
+struct _one_ms {
+ short m:9; // size is 2
+ int q:27; // size is 6
+ short w:13; // size is 8
+ short e:3; // size is 8
+ char r:4; // size is 9
+ char t:7; // size is 10
+ short y:16; // size is 12
+ short u:1; // size is 14
+ char i:2; // size is 15
+ int a; // size is 19
+ char o:6; // size is 20
+ char s:2; // size is 20
+ short d:10; // size is 22
+ short f:4; // size is 22
+ char b; // size is 23
+ char g:1; // size is 24
+ short h:13; // size is 26
+ char j:8; // size is 27
+ char k:5; // size is 28
+ char c; // size is 29
+ int l:28; // size is 33
+ char z:7; // size is 34
+ int x:20; // size is 38
+} __attribute__((__ms_struct__));
+typedef struct _one_ms one_ms;
+
+static int a1[(sizeof(one_ms) == 38) - 1];
+
+#pragma pack(2)
+struct _two_ms {
+ short m:9;
+ int q:27;
+ short w:13;
+ short e:3;
+ char r:4;
+ char t:7;
+ short y:16;
+ short u:1;
+ char i:2;
+ int a;
+ char o:6;
+ char s:2;
+ short d:10;
+ short f:4;
+ char b;
+ char g:1;
+ short h:13;
+ char j:8;
+ char k:5;
+ char c;
+ int l:28;
+ char z:7;
+ int x:20;
+} __attribute__((__ms_struct__));
+
+typedef struct _two_ms two_ms;
+
+static int a2[(sizeof(two_ms) == 42) - 1];
+
+#pragma pack(4)
+struct _four_ms {
+ short m:9;
+ int q:27;
+ short w:13;
+ short e:3;
+ char r:4;
+ char t:7;
+ short y:16;
+ short u:1;
+ char i:2;
+ int a;
+ char o:6;
+ char s:2;
+ short d:10;
+ short f:4;
+ char b;
+ char g:1;
+ short h:13;
+ char j:8;
+ char k:5;
+ char c;
+ int l:28;
+ char z:7;
+ int x:20;
+} __attribute__((__ms_struct__));
+typedef struct _four_ms four_ms;
+
+static int a4[(sizeof(four_ms) == 48) - 1];
+
+#pragma pack(8)
+struct _eight_ms {
+ short m:9;
+ int q:27;
+ short w:13;
+ short e:3;
+ char r:4;
+ char t:7;
+ short y:16;
+ short u:1;
+ char i:2;
+ int a;
+ char o:6;
+ char s:2;
+ short d:10;
+ short f:4;
+ char b;
+ char g:1;
+ short h:13;
+ char j:8;
+ char k:5;
+ char c;
+ int l:28;
+ char z:7;
+ int x:20;
+} __attribute__((__ms_struct__));
+
+typedef struct _eight_ms eight_ms;
+
+static int a8[(sizeof(eight_ms) == 48) - 1];
+
diff --git a/test/CodeGen/ms_struct.c b/test/CodeGen/ms_struct.c
new file mode 100644
index 0000000..a5f9606
--- /dev/null
+++ b/test/CodeGen/ms_struct.c
@@ -0,0 +1,23 @@
+// RUN: %clang_cc1 -triple i386-apple-darwin10 -emit-llvm %s -o - | FileCheck %s
+
+#define ATTR __attribute__((__ms_struct__))
+struct s1 {
+ int f32;
+ long long f64;
+} ATTR s1;
+
+// CHECK: %struct.s1 = type { i32, [4 x i8], i64 }
+
+struct s2 {
+ int f32;
+ long long f64[4];
+} ATTR s2;
+
+// CHECK: %struct.s2 = type { i32, [4 x i8], [4 x i64] }
+
+struct s3 {
+ int f32;
+ struct s1 s;
+} ATTR s3;
+
+// CHECK: %struct.s3 = type { i32, [4 x i8], %struct.s1 }
diff --git a/test/CodeGen/packed-arrays.c b/test/CodeGen/packed-arrays.c
index 785db4d..0c8bb6c 100644
--- a/test/CodeGen/packed-arrays.c
+++ b/test/CodeGen/packed-arrays.c
@@ -34,10 +34,8 @@ int align3 = __alignof(struct s3);
// CHECK: @align0_x = global i32 1
int align0_x = __alignof(((struct s0*) 0)->x);
-// We are currently incompatible with GCC here. <rdar://problem/9217290>
//
-// CHECK-XFAIL: @align1_x = global i32 1
-// CHECK: @align1_x = global i32 4
+// CHECK: @align1_x = global i32 1
int align1_x = __alignof(((struct s1*) 0)->x);
// CHECK: @align2_x = global i32 1
int align2_x = __alignof(((struct s2*) 0)->x);
@@ -66,22 +64,22 @@ int f0_b(struct s0 *a) {
return *(a->x + 1);
}
+// Note that we are incompatible with GCC on this example.
+//
// CHECK: define i32 @f1_a
-// CHECK: load i32* %{{.*}}, align 4
+// CHECK: load i32* %{{.*}}, align 1
// CHECK: }
// CHECK: define i32 @f1_b
// CHECK: load i32* %{{.*}}, align 4
// CHECK: }
-// Note that we are incompatible with GCC on these two examples.
+// Note that we are incompatible with GCC on this example.
//
// CHECK: define i32 @f1_c
-// CHECK-XFAIL: load i32* %{{.*}}, align 1
// CHECK: load i32* %{{.*}}, align 4
// CHECK: }
// CHECK: define i32 @f1_d
-// CHECK-XFAIL: load i32* %{{.*}}, align 1
-// CHECK: load i32* %{{.*}}, align 4
+// CHECK: load i32* %{{.*}}, align 1
// CHECK: }
int f1_a(struct s1 *a) {
return a->x[1];
diff --git a/test/CodeGen/packed-structure.c b/test/CodeGen/packed-structure.c
index 731a50b..3aeaa23 100644
--- a/test/CodeGen/packed-structure.c
+++ b/test/CodeGen/packed-structure.c
@@ -10,8 +10,7 @@ struct s0 {
// CHECK-GLOBAL: @s0_align_x = global i32 4
-// FIXME: This should be 1 to match gcc. PR7951.
-// CHECK-GLOBAL: @s0_align_y = global i32 4
+// CHECK-GLOBAL: @s0_align_y = global i32 1
// CHECK-GLOBAL: @s0_align = global i32 4
int s0_align_x = __alignof(((struct s0*)0)->x);
@@ -27,7 +26,7 @@ int s0_load_x(struct s0 *a) { return a->x; }
// with align 1 (in 2363.1 at least).
//
// CHECK-FUNCTIONS: define i32 @s0_load_y
-// CHECK-FUNCTIONS: [[s0_load_y:%.*]] = load i32* {{.*}}, align 4
+// CHECK-FUNCTIONS: [[s0_load_y:%.*]] = load i32* {{.*}}, align 1
// CHECK-FUNCTIONS: ret i32 [[s0_load_y]]
int s0_load_y(struct s0 *a) { return a->y; }
// CHECK-FUNCTIONS: define void @s0_copy
@@ -92,11 +91,11 @@ struct __attribute__((packed, aligned)) s3 {
short aShort;
int anInt;
};
-// CHECK-GLOBAL: @s3_1 = global i32 2
+// CHECK-GLOBAL: @s3_1 = global i32 1
int s3_1 = __alignof(((struct s3*) 0)->anInt);
// CHECK-FUNCTIONS: define i32 @test3(
int test3(struct s3 *ptr) {
// CHECK-FUNCTIONS: [[PTR:%.*]] = getelementptr inbounds {{%.*}}* {{%.*}}, i32 0, i32 1
- // CHECK-FUNCTIONS-NEXT: load i32* [[PTR]], align 2
+ // CHECK-FUNCTIONS-NEXT: load i32* [[PTR]], align 1
return ptr->anInt;
}
diff --git a/test/CodeGen/palignr.c b/test/CodeGen/palignr.c
index ed86c9e..1712df5 100644
--- a/test/CodeGen/palignr.c
+++ b/test/CodeGen/palignr.c
@@ -1,3 +1,4 @@
+// REQUIRES: x86-registered-target
// RUN: %clang_cc1 %s -triple=i686-apple-darwin -target-feature +ssse3 -O1 -S -o - | FileCheck %s
#define _mm_alignr_epi8(a, b, n) (__builtin_ia32_palignr128((a), (b), (n)))
diff --git a/test/CodeGen/string-literal-short-wstring.c b/test/CodeGen/string-literal-short-wstring.c
index 8c2e412..ce29904 100644
--- a/test/CodeGen/string-literal-short-wstring.c
+++ b/test/CodeGen/string-literal-short-wstring.c
@@ -3,7 +3,7 @@
int main() {
// This should convert to utf8.
- // CHECK: internal constant [10 x i8] c"\E1\84\A0\C8\A0\F4\82\80\B0\00", align 1
+ // CHECK: internal unnamed_addr constant [10 x i8] c"\E1\84\A0\C8\A0\F4\82\80\B0\00", align 1
char b[10] = "\u1120\u0220\U00102030";
// CHECK: private unnamed_addr constant [6 x i8] c"A\00B\00\00\00"
diff --git a/test/CodeGen/string-literal.c b/test/CodeGen/string-literal.c
index 6d02b0f..cc6c094 100644
--- a/test/CodeGen/string-literal.c
+++ b/test/CodeGen/string-literal.c
@@ -1,16 +1,16 @@
// RUN: %clang_cc1 -triple i386-unknown-unknown -emit-llvm %s -o - | FileCheck %s
int main() {
- // CHECK: internal constant [10 x i8] c"abc\00\00\00\00\00\00\00", align 1
+ // CHECK: internal unnamed_addr constant [10 x i8] c"abc\00\00\00\00\00\00\00", align 1
char a[10] = "abc";
// This should convert to utf8.
- // CHECK: internal constant [10 x i8] c"\E1\84\A0\C8\A0\F4\82\80\B0\00", align 1
+ // CHECK: internal unnamed_addr constant [10 x i8] c"\E1\84\A0\C8\A0\F4\82\80\B0\00", align 1
char b[10] = "\u1120\u0220\U00102030";
- // CHECK: private unnamed_addr constant [12 x i8] c"A\00\00\00B\00\00\00\00\00\00\00"
+ // CHECK: private unnamed_addr constant [12 x i8] c"A\00\00\00B\00\00\00\00\00\00\00", align 1
void *foo = L"AB";
- // CHECK: private unnamed_addr constant [12 x i8] c"4\12\00\00\0B\F0\10\00\00\00\00\00"
+ // CHECK: private unnamed_addr constant [12 x i8] c"4\12\00\00\0B\F0\10\00\00\00\00\00", align 1
void *bar = L"\u1234\U0010F00B";
}
diff --git a/test/CodeGen/struct-passing.c b/test/CodeGen/struct-passing.c
index 3e173be..8e5c0ad 100644
--- a/test/CodeGen/struct-passing.c
+++ b/test/CodeGen/struct-passing.c
@@ -20,5 +20,5 @@ void *ps[] = { f0, f1, f2, f3, f4, f5 };
// CHECK: declare i32 @f1() readonly
// CHECK: declare void @f2({{.*}} sret)
// CHECK: declare void @f3({{.*}} sret)
-// CHECK: declare void @f4({{.*}} byval)
-// CHECK: declare void @f5({{.*}} byval)
+// CHECK: declare void @f4({{.*}} byval align 4)
+// CHECK: declare void @f5({{.*}} byval align 4)
diff --git a/test/CodeGen/transparent-union.c b/test/CodeGen/transparent-union.c
index 97a7318..afdb3d6 100644
--- a/test/CodeGen/transparent-union.c
+++ b/test/CodeGen/transparent-union.c
@@ -11,7 +11,7 @@ typedef union {
void f0(transp_t0 obj);
// CHECK: define void @f1_0(i32* %a0)
-// CHECK: call void @f0(%union.transp_t0* byval %{{.*}})
+// CHECK: call void @f0(%union.transp_t0* byval align 4 %{{.*}})
// CHECK: call void %{{.*}}(i8* %{{[a-z0-9]*}})
// CHECK: }
void f1_0(int *a0) {
diff --git a/test/CodeGen/x86_32-arguments-darwin.c b/test/CodeGen/x86_32-arguments-darwin.c
index cf89de3..f7e2a53 100644
--- a/test/CodeGen/x86_32-arguments-darwin.c
+++ b/test/CodeGen/x86_32-arguments-darwin.c
@@ -53,7 +53,7 @@ void f8_2(struct s8 a0) {}
// FIXME: llvm-gcc expands this, this may have some value for the
// backend in terms of optimization but doesn't change the ABI.
-// CHECK: define void @f9_2(%struct.s9* byval %a0)
+// CHECK: define void @f9_2(%struct.s9* byval align 4 %a0)
struct s9 {
int a : 17;
int b;
@@ -229,7 +229,7 @@ typedef int v4i32 __attribute__((__vector_size__(16)));
v4i32 f55(v4i32 arg) { return arg+arg; }
// CHECK: define void @f56(
-// CHECK: i8 signext %a0, %struct.s56_0* byval %a1,
+// CHECK: i8 signext %a0, %struct.s56_0* byval align 4 %a1,
// CHECK: x86_mmx %a2.coerce, %struct.s56_1* byval align 4,
// CHECK: i64 %a4.coerce, %struct.s56_2* byval align 4,
// CHECK: <4 x i32> %a6, %struct.s39* byval align 16 %a7,
@@ -238,7 +238,7 @@ v4i32 f55(v4i32 arg) { return arg+arg; }
// CHECK: <4 x double> %a12, %struct.s56_6* byval align 4)
// CHECK: call void (i32, ...)* @f56_0(i32 1,
-// CHECK: i32 %{{[^ ]*}}, %struct.s56_0* byval %{{[^ ]*}},
+// CHECK: i32 %{{[^ ]*}}, %struct.s56_0* byval align 4 %{{[^ ]*}},
// CHECK: x86_mmx %{{[^ ]*}}, %struct.s56_1* byval align 4 %{{[^ ]*}},
// CHECK: i64 %{{[^ ]*}}, %struct.s56_2* byval align 4 %{{[^ ]*}},
// CHECK: <4 x i32> %{{[^ ]*}}, %struct.s39* byval align 16 %{{[^ ]*}},
diff --git a/test/CodeGen/x86_32-arguments-linux.c b/test/CodeGen/x86_32-arguments-linux.c
index 230a20d..2f246f8 100644
--- a/test/CodeGen/x86_32-arguments-linux.c
+++ b/test/CodeGen/x86_32-arguments-linux.c
@@ -2,7 +2,7 @@
// RUN: FileCheck < %t %s
// CHECK: define void @f56(
-// CHECK: i8 signext %a0, %struct.s56_0* byval %a1,
+// CHECK: i8 signext %a0, %struct.s56_0* byval align 4 %a1,
// CHECK: x86_mmx %a2.coerce, %struct.s56_1* byval align 4,
// CHECK: <1 x double> %a4, %struct.s56_2* byval align 4,
// CHECK: <4 x i32> %a6, %struct.s56_3* byval align 4,
@@ -11,7 +11,7 @@
// CHECK: <4 x double> %a12, %struct.s56_6* byval align 4)
// CHECK: call void (i32, ...)* @f56_0(i32 1,
-// CHECK: i32 %{{.*}}, %struct.s56_0* byval %{{[^ ]*}},
+// CHECK: i32 %{{.*}}, %struct.s56_0* byval align 4 %{{[^ ]*}},
// CHECK: x86_mmx %{{[^ ]*}}, %struct.s56_1* byval align 4 %{{[^ ]*}},
// CHECK: <1 x double> %{{[^ ]*}}, %struct.s56_2* byval align 4 %{{[^ ]*}},
// CHECK: <4 x i32> %{{[^ ]*}}, %struct.s56_3* byval align 4 %{{[^ ]*}},
diff --git a/test/CodeGen/x86_64-arguments.c b/test/CodeGen/x86_64-arguments.c
index ebde884..75c4788 100644
--- a/test/CodeGen/x86_64-arguments.c
+++ b/test/CodeGen/x86_64-arguments.c
@@ -69,7 +69,7 @@ void f12_1(struct s12 a0) {}
// Check that sret parameter is accounted for when checking available integer
// registers.
-// CHECK: define void @f13(%struct.s13_0* sret %agg.result, i32 %a, i32 %b, i32 %c, i32 %d, {{.*}}* byval %e, i32 %f)
+// CHECK: define void @f13(%struct.s13_0* sret %agg.result, i32 %a, i32 %b, i32 %c, i32 %d, {{.*}}* byval align 8 %e, i32 %f)
struct s13_0 { long long f0[3]; };
struct s13_1 { long long f0[2]; };
diff --git a/test/CodeGenCXX/PR5050-constructor-conversion.cpp b/test/CodeGenCXX/PR5050-constructor-conversion.cpp
index aa75ea4..9b993f2 100644
--- a/test/CodeGenCXX/PR5050-constructor-conversion.cpp
+++ b/test/CodeGenCXX/PR5050-constructor-conversion.cpp
@@ -1,3 +1,4 @@
+// REQUIRES: x86-registered-target,x86-64-registered-target
// RUN: %clang_cc1 -triple x86_64-apple-darwin -std=c++0x -S %s -o %t-64.s
// RUN: FileCheck -check-prefix LP64 --input-file=%t-64.s %s
// RUN: %clang_cc1 -triple i386-apple-darwin -std=c++0x -S %s -o %t-32.s
diff --git a/test/CodeGenCXX/abstract-class-ctors-dtors.cpp b/test/CodeGenCXX/abstract-class-ctors-dtors.cpp
new file mode 100644
index 0000000..e1c1a75
--- /dev/null
+++ b/test/CodeGenCXX/abstract-class-ctors-dtors.cpp
@@ -0,0 +1,16 @@
+// RUN: %clang_cc1 %s -triple x86_64-apple-darwin10 -emit-llvm -o - | FileCheck %s
+
+// Check that we dont emit the complete constructor/destructor for this class.
+struct A {
+ virtual void f() = 0;
+ A();
+ ~A();
+};
+
+// CHECK-NOT: define void @_ZN1AC1Ev
+// CHECK: define void @_ZN1AC2Ev
+// CHECK-NOT: define void @_ZN1AD1Ev
+// CHECK: define void @_ZN1AD2Ev
+A::A() { }
+
+A::~A() { }
diff --git a/test/CodeGenCXX/arm.cpp b/test/CodeGenCXX/arm.cpp
index 8d74d00..dcb27ce 100644
--- a/test/CodeGenCXX/arm.cpp
+++ b/test/CodeGenCXX/arm.cpp
@@ -136,8 +136,8 @@ namespace test3 {
void d(int n) {
// CHECK: define void @_ZN5test31dEi(
// CHECK: [[N:%.*]] = load i32*
- // CHECK: [[NE:%.*]] = mul i32 [[N]], 20
// CHECK: @llvm.umul.with.overflow.i32(i32 [[N]], i32 80)
+ // CHECK: [[NE:%.*]] = mul i32 [[N]], 20
// CHECK: @llvm.uadd.with.overflow.i32(i32 {{.*}}, i32 8)
// CHECK: [[SZ:%.*]] = select
// CHECK: call noalias i8* @_Znam(i32 [[SZ]])
@@ -208,8 +208,8 @@ namespace test4 {
void d(int n) {
// CHECK: define void @_ZN5test41dEi(
// CHECK: [[N:%.*]] = load i32*
- // CHECK: [[NE:%.*]] = mul i32 [[N]], 20
// CHECK: @llvm.umul.with.overflow.i32(i32 [[N]], i32 80)
+ // CHECK: [[NE:%.*]] = mul i32 [[N]], 20
// CHECK: @llvm.uadd.with.overflow.i32(i32 {{.*}}, i32 8)
// CHECK: [[SZ:%.*]] = select
// CHECK: call noalias i8* @_Znam(i32 [[SZ]])
@@ -310,7 +310,7 @@ namespace test7 {
// CHECK: call i8* @llvm.eh.exception()
// CHECK: call void @__cxa_guard_abort(i32* @_ZGVZN5test74testEvE1x)
- // CHECK: call void @_Unwind_Resume_or_Rethrow
+ // CHECK: call void @llvm.eh.resume(
}
}
@@ -349,7 +349,7 @@ namespace test8 {
// CHECK: call i8* @llvm.eh.exception()
// CHECK: call void @__cxa_guard_abort(i32* @_ZGVZN5test84testEvE1x)
- // CHECK: call void @_Unwind_Resume_or_Rethrow
+ // CHECK: call void @llvm.eh.resume(
}
}
diff --git a/test/CodeGenCXX/array-construction.cpp b/test/CodeGenCXX/array-construction.cpp
index d044ac5..5efe183 100644
--- a/test/CodeGenCXX/array-construction.cpp
+++ b/test/CodeGenCXX/array-construction.cpp
@@ -1,3 +1,4 @@
+// REQUIRES: x86-registered-target,x86-64-registered-target
// RUN: %clang_cc1 -triple x86_64-apple-darwin -std=c++0x -S %s -o %t-64.s
// RUN: FileCheck -check-prefix LP64 --input-file=%t-64.s %s
// RUN: %clang_cc1 -triple i386-apple-darwin -std=c++0x -S %s -o %t-32.s
diff --git a/test/CodeGenCXX/array-operator-delete-call.cpp b/test/CodeGenCXX/array-operator-delete-call.cpp
index ad60cf6..41b0118 100644
--- a/test/CodeGenCXX/array-operator-delete-call.cpp
+++ b/test/CodeGenCXX/array-operator-delete-call.cpp
@@ -1,3 +1,4 @@
+// REQUIRES: x86-registered-target,x86-64-registered-target
// RUN: %clang_cc1 -triple x86_64-apple-darwin -std=c++0x -S %s -o %t-64.s
// RUN: FileCheck -check-prefix LP64 --input-file=%t-64.s %s
// RUN: %clang_cc1 -triple i386-apple-darwin -std=c++0x -S %s -o %t-32.s
diff --git a/test/CodeGenCXX/call-arg-zero-temp.cpp b/test/CodeGenCXX/call-arg-zero-temp.cpp
index 88e7452..101e81f 100644
--- a/test/CodeGenCXX/call-arg-zero-temp.cpp
+++ b/test/CodeGenCXX/call-arg-zero-temp.cpp
@@ -1,3 +1,4 @@
+// REQUIRES: x86-registered-target,x86-64-registered-target
// RUN: %clang_cc1 -triple x86_64-apple-darwin -S %s -o %t-64.s
// RUN: FileCheck -check-prefix LP64 --input-file=%t-64.s %s
// RUN: %clang_cc1 -triple i386-apple-darwin -S %s -o %t-32.s
diff --git a/test/CodeGenCXX/cast-conversion.cpp b/test/CodeGenCXX/cast-conversion.cpp
index 27e34b9..b7a9740 100644
--- a/test/CodeGenCXX/cast-conversion.cpp
+++ b/test/CodeGenCXX/cast-conversion.cpp
@@ -1,3 +1,4 @@
+// REQUIRES: x86-registered-target,x86-64-registered-target
// RUN: %clang_cc1 -triple x86_64-apple-darwin -std=c++0x -S %s -o %t-64.s
// RUN: FileCheck -check-prefix LP64 --input-file=%t-64.s %s
// RUN: %clang_cc1 -triple i386-apple-darwin -std=c++0x -S %s -o %t-32.s
diff --git a/test/CodeGenCXX/constructor-conversion.cpp b/test/CodeGenCXX/constructor-conversion.cpp
index 405bba6..58d0d39 100644
--- a/test/CodeGenCXX/constructor-conversion.cpp
+++ b/test/CodeGenCXX/constructor-conversion.cpp
@@ -1,3 +1,4 @@
+// REQUIRES: x86-registered-target,x86-64-registered-target
// RUN: %clang_cc1 -triple x86_64-apple-darwin -std=c++0x -S %s -o %t-64.s
// RUN: FileCheck -check-prefix LP64 --input-file=%t-64.s %s
// RUN: %clang_cc1 -triple i386-apple-darwin -std=c++0x -S %s -o %t-32.s
diff --git a/test/CodeGenCXX/constructor-default-arg.cpp b/test/CodeGenCXX/constructor-default-arg.cpp
index 0c08c76..dc0ab50 100644
--- a/test/CodeGenCXX/constructor-default-arg.cpp
+++ b/test/CodeGenCXX/constructor-default-arg.cpp
@@ -1,3 +1,4 @@
+// REQUIRES: x86-registered-target,x86-64-registered-target
// RUN: %clang_cc1 -triple x86_64-apple-darwin -std=c++0x -S %s -o %t-64.s
// RUN: FileCheck -check-prefix LP64 --input-file=%t-64.s %s
// RUN: %clang_cc1 -triple i386-apple-darwin -std=c++0x -S %s -o %t-32.s
diff --git a/test/CodeGenCXX/constructor-for-array-members.cpp b/test/CodeGenCXX/constructor-for-array-members.cpp
index fd6dc6d..ef5900e 100644
--- a/test/CodeGenCXX/constructor-for-array-members.cpp
+++ b/test/CodeGenCXX/constructor-for-array-members.cpp
@@ -1,3 +1,4 @@
+// REQUIRES: x86-registered-target,x86-64-registered-target
// RUN: %clang_cc1 -triple x86_64-apple-darwin -std=c++0x -S %s -o %t-64.s
// RUN: FileCheck -check-prefix LP64 --input-file=%t-64.s %s
// RUN: %clang_cc1 -triple i386-apple-darwin -std=c++0x -S %s -o %t-32.s
diff --git a/test/CodeGenCXX/constructor-template.cpp b/test/CodeGenCXX/constructor-template.cpp
index a3f38a6..7472d7e 100644
--- a/test/CodeGenCXX/constructor-template.cpp
+++ b/test/CodeGenCXX/constructor-template.cpp
@@ -1,3 +1,4 @@
+// REQUIRES: x86-registered-target,x86-64-registered-target
// RUN: %clang_cc1 -triple x86_64-apple-darwin -std=c++0x -S %s -o %t-64.s
// RUN: FileCheck -check-prefix LP64 --input-file=%t-64.s %s
// RUN: %clang_cc1 -triple i386-apple-darwin -std=c++0x -S %s -o %t-32.s
diff --git a/test/CodeGenCXX/convert-to-fptr.cpp b/test/CodeGenCXX/convert-to-fptr.cpp
index f895dbc..c1c9f63 100644
--- a/test/CodeGenCXX/convert-to-fptr.cpp
+++ b/test/CodeGenCXX/convert-to-fptr.cpp
@@ -1,3 +1,4 @@
+// REQUIRES: x86-registered-target,x86-64-registered-target
// RUN: %clang_cc1 -triple x86_64-apple-darwin -std=c++0x -S %s -o %t-64.s
// RUN: FileCheck -check-prefix LP64 --input-file=%t-64.s %s
// RUN: %clang_cc1 -triple i386-apple-darwin -std=c++0x -S %s -o %t-32.s
diff --git a/test/CodeGenCXX/copy-assign-synthesis-1.cpp b/test/CodeGenCXX/copy-assign-synthesis-1.cpp
index eb761c2..17abeb9 100644
--- a/test/CodeGenCXX/copy-assign-synthesis-1.cpp
+++ b/test/CodeGenCXX/copy-assign-synthesis-1.cpp
@@ -1,3 +1,4 @@
+// REQUIRES: x86-registered-target,x86-64-registered-target
// RUN: %clang_cc1 -triple x86_64-apple-darwin -std=c++0x -S %s -o %t-64.s
// RUN: FileCheck -check-prefix LP64 --input-file=%t-64.s %s
// RUN: %clang_cc1 -triple i386-apple-darwin -std=c++0x -S %s -o %t-32.s
diff --git a/test/CodeGenCXX/cxx0x-defaulted-templates.cpp b/test/CodeGenCXX/cxx0x-defaulted-templates.cpp
new file mode 100644
index 0000000..3d4000e
--- /dev/null
+++ b/test/CodeGenCXX/cxx0x-defaulted-templates.cpp
@@ -0,0 +1,19 @@
+// RUN: %clang_cc1 -std=c++0x -emit-llvm -o - %s | FileCheck %s
+
+template <typename T>
+struct X {
+ X();
+};
+
+// CHECK: define void @_ZN1XIbEC1Ev
+// CHECK: define void @_ZN1XIbEC2Ev
+template <> X<bool>::X() = default;
+
+// CHECK: define weak_odr void @_ZN1XIiEC1Ev
+// CHECK: define weak_odr void @_ZN1XIiEC2Ev
+template <typename T> X<T>::X() = default;
+template X<int>::X();
+
+// CHECK: define linkonce_odr void @_ZN1XIcEC1Ev
+// CHECK: define linkonce_odr void @_ZN1XIcEC2Ev
+X<char> x;
diff --git a/test/CodeGenCXX/cxx0x-delegating-ctors.cpp b/test/CodeGenCXX/cxx0x-delegating-ctors.cpp
index 5b432c7..15c8e7f 100644
--- a/test/CodeGenCXX/cxx0x-delegating-ctors.cpp
+++ b/test/CodeGenCXX/cxx0x-delegating-ctors.cpp
@@ -2,10 +2,10 @@
struct non_trivial {
non_trivial();
- ~non_trivial();
+ ~non_trivial() noexcept(false);
};
non_trivial::non_trivial() {}
-non_trivial::~non_trivial() {}
+non_trivial::~non_trivial() noexcept(false) {}
// We use a virtual base to ensure that the constructor
// delegation optimization (complete->base) can't be
@@ -22,27 +22,35 @@ delegator::delegator() {
throw 0;
}
-// CHECK: define void @_ZN9delegatorC1Ei
-// CHECK: call void @_ZN9delegatorC1Ev
-// CHECK-NOT: lpad
-// CHECK: ret
-// CHECK-NOT: lpad
-// CHECK: define void @_ZN9delegatorC2Ei
-// CHECK: call void @_ZN9delegatorC2Ev
-// CHECK-NOT: lpad
-// CHECK: ret
-// CHECK-NOT: lpad
-delegator::delegator(int)
- : delegator()
-{}
delegator::delegator(bool)
{}
+// CHECK: define void @_ZN9delegatorC1Ec
+// CHECK: void @_ZN9delegatorC1Eb
+// CHECK: void @__cxa_throw
+// CHECK: void @_ZSt9terminatev
+// CHECK: void @_ZN9delegatorD1Ev
// CHECK: define void @_ZN9delegatorC2Ec
-// CHECK: call void @_ZN9delegatorC2Eb
-// CHECK: call void @__cxa_throw
+// CHECK: void @_ZN9delegatorC2Eb
+// CHECK: void @__cxa_throw
+// CHECK: void @_ZSt9terminatev
+// CHECK: void @_ZN9delegatorD2Ev
delegator::delegator(char)
: delegator(true) {
throw 0;
}
+
+// CHECK: define void @_ZN9delegatorC1Ei
+// CHECK: void @_ZN9delegatorC1Ev
+// CHECK-NOT: void @_ZSt9terminatev
+// CHECK: ret
+// CHECK-NOT: void @_ZSt9terminatev
+// CHECK: define void @_ZN9delegatorC2Ei
+// CHECK: void @_ZN9delegatorC2Ev
+// CHECK-NOT: void @_ZSt9terminatev
+// CHECK: ret
+// CHECK-NOT: void @_ZSt9terminatev
+delegator::delegator(int)
+ : delegator()
+{}
diff --git a/test/CodeGenCXX/debug-info-pubtypes.cpp b/test/CodeGenCXX/debug-info-pubtypes.cpp
new file mode 100644
index 0000000..35ba90b
--- /dev/null
+++ b/test/CodeGenCXX/debug-info-pubtypes.cpp
@@ -0,0 +1,15 @@
+// REQUIRES: x86-64-registered-target
+// RUN: %clang -cc1 -triple x86_64-apple-darwin10 -g -S %s -o %t
+// RUN: FileCheck %s < %t
+
+//CHECK: .asciz "G"
+//CHECK-NEXT: .long 0
+//CHECK-NEXT: Lpubtypes_end1:
+
+class G {
+public:
+ void foo();
+};
+
+void G::foo() {
+}
diff --git a/test/CodeGenCXX/decl-ref-init.cpp b/test/CodeGenCXX/decl-ref-init.cpp
index 58fdeda..a066fbb 100644
--- a/test/CodeGenCXX/decl-ref-init.cpp
+++ b/test/CodeGenCXX/decl-ref-init.cpp
@@ -1,3 +1,4 @@
+// REQUIRES: x86-registered-target,x86-64-registered-target
// RUN: %clang_cc1 -triple x86_64-apple-darwin -S %s -o %t-64.s
// RUN: FileCheck -check-prefix LP64 --input-file=%t-64.s %s
// RUN: %clang_cc1 -triple i386-apple-darwin -S %s -o %t-32.s
diff --git a/test/CodeGenCXX/default-constructor-for-members.cpp b/test/CodeGenCXX/default-constructor-for-members.cpp
index a97764d..714811f 100644
--- a/test/CodeGenCXX/default-constructor-for-members.cpp
+++ b/test/CodeGenCXX/default-constructor-for-members.cpp
@@ -1,3 +1,4 @@
+// REQUIRES: x86-registered-target,x86-64-registered-target
// RUN: %clang_cc1 -triple x86_64-apple-darwin -S %s -o %t-64.s
// RUN: FileCheck -check-prefix LP64 --input-file=%t-64.s %s
// RUN: %clang_cc1 -triple i386-apple-darwin -S %s -o %t-32.s
diff --git a/test/CodeGenCXX/derived-to-base-conv.cpp b/test/CodeGenCXX/derived-to-base-conv.cpp
index 006f264..c47c831 100644
--- a/test/CodeGenCXX/derived-to-base-conv.cpp
+++ b/test/CodeGenCXX/derived-to-base-conv.cpp
@@ -1,3 +1,4 @@
+// REQUIRES: x86-registered-target,x86-64-registered-target
// RUN: %clang_cc1 -triple x86_64-apple-darwin -std=c++0x -S %s -o %t-64.s
// RUN: FileCheck -check-prefix LP64 --input-file=%t-64.s %s
// RUN: %clang_cc1 -triple i386-apple-darwin -std=c++0x -S %s -o %t-32.s
diff --git a/test/CodeGenCXX/destructors.cpp b/test/CodeGenCXX/destructors.cpp
index 353b610..94d8833 100644
--- a/test/CodeGenCXX/destructors.cpp
+++ b/test/CodeGenCXX/destructors.cpp
@@ -334,7 +334,7 @@ namespace test7 {
// CHECK: ret void
// CHECK: call i8* @llvm.eh.exception(
// CHECK: call void @_ZdlPv({{.*}}) nounwind
- // CHECK: call void @_Unwind_Resume_or_Rethrow
+ // CHECK: call void @llvm.eh.resume(
// Checked at top of file:
// @_ZN5test312_GLOBAL__N_11DD1Ev = alias internal {{.*}} @_ZN5test312_GLOBAL__N_11DD2Ev
@@ -364,7 +364,7 @@ namespace test7 {
// CHECK: ret void
// CHECK: call i8* @llvm.eh.exception()
// CHECK: call void @_ZdlPv({{.*}}) nounwind
- // CHECK: call void @_Unwind_Resume_or_Rethrow(
+ // CHECK: call void @llvm.eh.resume(
// CHECK: define internal void @_ZThn8_N5test312_GLOBAL__N_11CD1Ev(
// CHECK: getelementptr inbounds i8* {{.*}}, i64 -8
diff --git a/test/CodeGenCXX/eh.cpp b/test/CodeGenCXX/eh.cpp
index 6c44c76..44219b4 100644
--- a/test/CodeGenCXX/eh.cpp
+++ b/test/CodeGenCXX/eh.cpp
@@ -30,7 +30,8 @@ void test2() {
}
// CHECK: define void @_Z5test2v()
-// CHECK: [[EXNSLOTVAR:%.*]] = alloca i8*
+// CHECK: [[EXNVAR:%.*]] = alloca i8*
+// CHECK-NEXT: [[SELECTORVAR:%.*]] = alloca i32
// CHECK-NEXT: [[CLEANUPDESTVAR:%.*]] = alloca i32
// CHECK-NEXT: [[EXNOBJ:%.*]] = call i8* @__cxa_allocate_exception(i64 16)
// CHECK-NEXT: [[EXN:%.*]] = bitcast i8* [[EXNOBJ]] to [[DSTAR:%[^*]*\*]]
@@ -104,6 +105,7 @@ namespace test7 {
// CHECK: define i32 @_ZN5test73fooEv()
int foo() {
// CHECK: [[CAUGHTEXNVAR:%.*]] = alloca i8*
+// CHECK-NEXT: [[SELECTORVAR:%.*]] = alloca i32
// CHECK-NEXT: [[INTCATCHVAR:%.*]] = alloca i32
// CHECK-NEXT: [[EHCLEANUPDESTVAR:%.*]] = alloca i32
try {
@@ -117,7 +119,8 @@ namespace test7 {
// CHECK: [[CAUGHTEXN:%.*]] = call i8* @llvm.eh.exception()
// CHECK-NEXT: store i8* [[CAUGHTEXN]], i8** [[CAUGHTEXNVAR]]
-// CHECK-NEXT: call i32 (i8*, i8*, ...)* @llvm.eh.selector(i8* [[CAUGHTEXN]], i8* bitcast (i32 (...)* @__gxx_personality_v0 to i8*), i8* bitcast (i8** @_ZTIi to i8*), i8* null)
+// CHECK-NEXT: [[SELECTOR:%.*]] = call i32 (i8*, i8*, ...)* @llvm.eh.selector(i8* [[CAUGHTEXN]], i8* bitcast (i32 (...)* @__gxx_personality_v0 to i8*), i8* bitcast (i8** @_ZTIi to i8*), i8* null)
+// CHECK-NEXT: store i32 [[SELECTOR]], i32* [[SELECTORVAR]]
// CHECK-NEXT: call i32 @llvm.eh.typeid.for(i8* bitcast (i8** @_ZTIi to i8*))
// CHECK-NEXT: icmp eq
// CHECK-NEXT: br i1
@@ -130,7 +133,8 @@ namespace test7 {
}
// CHECK: [[CAUGHTEXN:%.*]] = call i8* @llvm.eh.exception()
// CHECK-NEXT: store i8* [[CAUGHTEXN]], i8** [[CAUGHTEXNVAR]]
-// CHECK-NEXT: call i32 (i8*, i8*, ...)* @llvm.eh.selector(i8* [[CAUGHTEXN]], i8* bitcast (i32 (...)* @__gxx_personality_v0 to i8*), i8* null)
+// CHECK-NEXT: [[SELECTOR:%.*]] = call i32 (i8*, i8*, ...)* @llvm.eh.selector(i8* [[CAUGHTEXN]], i8* bitcast (i32 (...)* @__gxx_personality_v0 to i8*), i8* null)
+// CHECK-NEXT: store i32 [[SELECTOR]], i32* [[SELECTORVAR]]
// CHECK-NEXT: store i32 1, i32* [[EHCLEANUPDESTVAR]]
// CHECK-NEXT: call void @__cxa_end_catch()
// CHECK-NEXT: br label
@@ -159,7 +163,7 @@ namespace test8 {
// CHECK-NEXT: bitcast
// CHECK-NEXT: invoke void @_ZN5test81AC1ERKS0_(
// CHECK: call i8* @__cxa_begin_catch
- // CHECK-NEXT: invoke void @_ZN5test81AD1Ev(
+ // CHECK-NEXT: call void @_ZN5test81AD1Ev(
// CHECK: call void @__cxa_end_catch()
// CHECK: ret void
}
@@ -190,7 +194,7 @@ namespace test9 {
// landing pad from first call to invoke
// CHECK: call i8* @llvm.eh.exception
- // CHECK: call i32 (i8*, i8*, ...)* @llvm.eh.selector(i8* {{.*}}, i8* bitcast (i32 (...)* @__gxx_personality_v0 to i8*), i8* bitcast (i8** @_ZTIi to i8*), i8* null)
+ // CHECK: call i32 (i8*, i8*, ...)* @llvm.eh.selector(i8* {{.*}}, i8* bitcast (i32 (...)* @__gxx_personality_v0 to i8*), i8* bitcast (i8** @_ZTIi to i8*))
}
// __cxa_end_catch can throw for some kinds of caught exceptions.
@@ -255,6 +259,7 @@ namespace test11 {
void bar() {
try {
// CHECK: [[EXNSLOT:%.*]] = alloca i8*
+ // CHECK-NEXT: [[SELECTORSLOT:%.*]] = alloca i32
// CHECK-NEXT: [[P:%.*]] = alloca [[A:%.*]]**,
// CHECK-NEXT: [[TMP:%.*]] = alloca [[A]]*
// CHECK-NEXT: invoke void @_ZN6test116opaqueEv()
@@ -272,7 +277,7 @@ namespace test11 {
// PR7686
namespace test12 {
- struct A { ~A(); };
+ struct A { ~A() noexcept(false); };
bool opaque(const A&);
// CHECK: define void @_ZN6test124testEv()
@@ -392,8 +397,8 @@ namespace test15 {
}
namespace test16 {
- struct A { A(); ~A(); };
- struct B { int x; B(const A &); ~B(); };
+ struct A { A(); ~A() noexcept(false); };
+ struct B { int x; B(const A &); ~B() noexcept(false); };
void foo();
bool cond();
@@ -403,6 +408,7 @@ namespace test16 {
// CHECK-NEXT: [[EXN_ACTIVE:%.*]] = alloca i1
// CHECK-NEXT: [[TEMP:%.*]] = alloca [[A:%.*]],
// CHECK-NEXT: [[EXNSLOT:%.*]] = alloca i8*
+ // CHECK-NEXT: [[SELECTORSLOT:%.*]] = alloca i32
// CHECK-NEXT: [[EHDEST:%.*]] = alloca i32
// CHECK-NEXT: [[TEMP_ACTIVE:%.*]] = alloca i1
diff --git a/test/CodeGenCXX/exceptions.cpp b/test/CodeGenCXX/exceptions.cpp
index d9b8506..b32b90b 100644
--- a/test/CodeGenCXX/exceptions.cpp
+++ b/test/CodeGenCXX/exceptions.cpp
@@ -273,6 +273,7 @@ namespace test5 {
// CHECK: define void @_ZN5test54testEv()
// CHECK: [[EXNSLOT:%.*]] = alloca i8*
+ // CHECK-NEXT: [[SELECTORSLOT:%.*]] = alloca i32
// CHECK-NEXT: [[A:%.*]] = alloca [[A_T:%.*]], align 1
// CHECK-NEXT: [[T:%.*]] = alloca [[T_T:%.*]], align 1
// CHECK-NEXT: alloca i32
@@ -324,6 +325,7 @@ namespace test7 {
// CHECK-NEXT: alloca [[A:%.*]],
// CHECK-NEXT: alloca i8*
// CHECK-NEXT: alloca i32
+ // CHECK-NEXT: alloca i32
// CHECK-NEXT: [[OUTER_A:%.*]] = alloca i1
// CHECK-NEXT: alloca i8*
// CHECK-NEXT: [[INNER_NEW:%.*]] = alloca i1
diff --git a/test/CodeGenCXX/global-array-destruction.cpp b/test/CodeGenCXX/global-array-destruction.cpp
index c77551c..bbe574d 100644
--- a/test/CodeGenCXX/global-array-destruction.cpp
+++ b/test/CodeGenCXX/global-array-destruction.cpp
@@ -1,3 +1,4 @@
+// REQUIRES: x86-64-registered-target
// RUN: %clang_cc1 -triple x86_64-apple-darwin -std=c++0x -S %s -o %t-64.s
// RUN: FileCheck -check-prefix LP64 --input-file=%t-64.s %s
diff --git a/test/CodeGenCXX/global-llvm-constant.cpp b/test/CodeGenCXX/global-llvm-constant.cpp
index ef1dcf0..2bd43b9 100644
--- a/test/CodeGenCXX/global-llvm-constant.cpp
+++ b/test/CodeGenCXX/global-llvm-constant.cpp
@@ -8,3 +8,25 @@ struct A {
const A x;
// CHECK: @_ZL1x = internal global
+
+struct X {
+ int (*fp)(int, int);
+};
+
+int add(int x, int y) { return x + y; }
+
+// CHECK: @x2 = constant
+extern const X x2;
+const X x2 = { &add };
+
+struct X1 {
+ mutable int i;
+};
+
+struct X2 {
+ X1 array[3];
+};
+
+// CHECK: @x2b = global
+extern const X2 x2b;
+const X2 x2b = { { { 1 }, { 2 }, { 3 } } };
diff --git a/test/CodeGenCXX/goto.cpp b/test/CodeGenCXX/goto.cpp
index 3286b22..9a12a91 100644
--- a/test/CodeGenCXX/goto.cpp
+++ b/test/CodeGenCXX/goto.cpp
@@ -12,6 +12,7 @@ namespace test0 {
// CHECK-NEXT: [[Y:%.*]] = alloca [[A:%.*]],
// CHECK-NEXT: [[Z:%.*]] = alloca [[A]]
// CHECK-NEXT: [[EXN:%.*]] = alloca i8*
+ // CHECK-NEXT: [[SEL:%.*]] = alloca i32
// CHECK-NEXT: alloca i32
// CHECK-NEXT: [[V:%.*]] = alloca [[V:%.*]]*,
// CHECK-NEXT: [[TMP:%.*]] = alloca [[A]]
diff --git a/test/CodeGenCXX/instrument-functions.cpp b/test/CodeGenCXX/instrument-functions.cpp
new file mode 100644
index 0000000..253e096
--- /dev/null
+++ b/test/CodeGenCXX/instrument-functions.cpp
@@ -0,0 +1,30 @@
+// RUN: %clang_cc1 -S -emit-llvm -o - %s -finstrument-functions | FileCheck %s
+
+// CHECK: @_Z5test1i
+int test1(int x) {
+// CHECK: __cyg_profile_func_enter
+// CHECK: __cyg_profile_func_exit
+// CHECK: ret
+ return x;
+}
+
+// CHECK: @_Z5test2i
+int test2(int) __attribute__((no_instrument_function));
+int test2(int x) {
+// CHECK-NOT: __cyg_profile_func_enter
+// CHECK-NOT: __cyg_profile_func_exit
+// CHECK: ret
+ return x;
+}
+
+// This test case previously crashed code generation. It exists solely
+// to test -finstrument-function does not crash codegen for this trivial
+// case.
+namespace rdar9445102 {
+ class Rdar9445102 {
+ public:
+ Rdar9445102();
+ };
+}
+static rdar9445102::Rdar9445102 s_rdar9445102Initializer;
+
diff --git a/test/CodeGenCXX/internal-linkage.cpp b/test/CodeGenCXX/internal-linkage.cpp
index 39bce85..56cb810 100644
--- a/test/CodeGenCXX/internal-linkage.cpp
+++ b/test/CodeGenCXX/internal-linkage.cpp
@@ -54,3 +54,11 @@ char const * *test4()
// CHECK: @extern_nonconst_xyzzy = global
return &extern_nonconst_xyzzy;
}
+
+// PR10120
+template <typename T> class klass {
+ virtual void f();
+};
+namespace { struct S; }
+void foo () { klass<S> x; }
+// CHECK: @_ZTV5klassIN12_GLOBAL__N_11SEE = internal unnamed_addr constant
diff --git a/test/CodeGenCXX/mangle-alias-template.cpp b/test/CodeGenCXX/mangle-alias-template.cpp
new file mode 100644
index 0000000..2020a0a
--- /dev/null
+++ b/test/CodeGenCXX/mangle-alias-template.cpp
@@ -0,0 +1,41 @@
+// RUN: %clang_cc1 -std=c++0x -triple x86_64-apple-darwin10 -emit-llvm -o - %s | FileCheck %s
+
+template<typename T> struct alloc {};
+template<typename T> using Alloc = alloc<T>;
+template<typename T, typename A = Alloc<T>> struct vector {};
+
+template<typename T> using Vec = vector<T>;
+
+template<typename T> void f(Vec<T> v);
+template<typename T> void g(T);
+
+template<template<typename> class F> void h(F<int>);
+
+// CHECK: define void @_Z1zv(
+void z() {
+ vector<int> VI;
+ f(VI);
+ // CHECK: call void @_Z1fIiEv6vectorIT_5allocIS1_EE(
+
+ Vec<double> VD;
+ g(VD);
+ // CHECK: call void @_Z1gI6vectorId5allocIdEEEvT_(
+
+ h<Vec>(VI);
+ // CHECK: call void @_Z1hI3VecEvT_IiE(
+
+ Alloc<int> AC;
+ h(AC);
+ // CHECK: call void @_Z1hI5allocEvT_IiE(
+
+ h<Alloc>(AC);
+ // CHECK: call void @_Z1hI5AllocEvT_IiE(
+
+ Vec<char> VC;
+ g<Vec<char>>(VC);
+ // CHECK: call void @_Z1gI6vectorIc5allocIcEEEvT_(
+
+ Vec<Vec<int>> VVI;
+ g(VVI);
+ // CHECK: call void @_Z1gI6vectorIS0_Ii5allocIiEES1_IS3_EEEvT_(
+}
diff --git a/test/CodeGenCXX/mangle-exprs.cpp b/test/CodeGenCXX/mangle-exprs.cpp
index 46c46f0..75294e0 100644
--- a/test/CodeGenCXX/mangle-exprs.cpp
+++ b/test/CodeGenCXX/mangle-exprs.cpp
@@ -109,3 +109,19 @@ namespace test2 {
// CHECK: store float {{.*}}, float* @_ZZN5test21gIPFfvEEEvT_DTclfL0p_EEE8variable,
}
+
+namespace test3 {
+ template <class T, class U> void a(T x, U y, decltype(x.*y) z) {}
+
+ struct X {
+ int *member;
+ };
+
+ // CHECK: define void @_ZN5test311instantiateEv
+ void instantiate() {
+ X x;
+ int *ip;
+ // CHECK: call void @_ZN5test31aINS_1XEMS1_PiEEvT_T0_DTdsfL0p_fL0p0_E
+ a(x, &X::member, ip);
+ }
+}
diff --git a/test/CodeGenCXX/mangle-subst-std.cpp b/test/CodeGenCXX/mangle-subst-std.cpp
index fea3582..837d4fa 100644
--- a/test/CodeGenCXX/mangle-subst-std.cpp
+++ b/test/CodeGenCXX/mangle-subst-std.cpp
@@ -11,6 +11,7 @@
// CHECK: @_ZTVSo = linkonce_odr unnamed_addr constant
// CHECK: @_ZTTSi = linkonce_odr unnamed_addr constant
// CHECK: @_ZTVSi = linkonce_odr unnamed_addr constant
+
namespace std {
struct A { A(); };
diff --git a/test/CodeGenCXX/mangle-unnameable-conversions.cpp b/test/CodeGenCXX/mangle-unnameable-conversions.cpp
new file mode 100644
index 0000000..2132eff
--- /dev/null
+++ b/test/CodeGenCXX/mangle-unnameable-conversions.cpp
@@ -0,0 +1,14 @@
+// RUN: %clang_cc1 -std=c++0x -triple x86_64-apple-darwin10 -emit-llvm -o - %s | FileCheck %s
+
+template<typename T> using id = T;
+struct S {
+ template<typename T, int N>
+ operator id<T[N]>&();
+ template<typename T, typename U>
+ operator id<T (U::*)()>() const;
+};
+
+void f() {
+ int (&a)[42] = S(); // CHECK: @_ZN1ScvRAT0__T_IiLi42EEEv(
+ char (S::*fp)() = S(); // CHECK: @_ZNK1ScvMT0_FT_vEIcS_EEv(
+};
diff --git a/test/CodeGenCXX/mangle.cpp b/test/CodeGenCXX/mangle.cpp
index 27777a5..01dcf8b 100644
--- a/test/CodeGenCXX/mangle.cpp
+++ b/test/CodeGenCXX/mangle.cpp
@@ -397,16 +397,16 @@ namespace test3 {
struct Path2 : AmbiguousBase { double p; };
struct Derived : Path1, Path2 { };
- // CHECK: define linkonce_odr i32 @_ZN5test38get_ab_1INS_7DerivedEEEDtptcvPT_Li0EsrNS_5Path1E2abERS2_(
+ // CHECK: define linkonce_odr i32 @_ZN5test38get_ab_1INS_7DerivedEEEDtptcvPT_Li0Esr5Path1E2abERS2_(
template <class T> decltype(((T*) 0)->Path1::ab) get_ab_1(T &ref) { return ref.Path1::ab; }
- // CHECK: define linkonce_odr i32 @_ZN5test38get_ab_2INS_7DerivedEEEDtptcvPT_Li0EsrNS_5Path2E2abERS2_(
+ // CHECK: define linkonce_odr i32 @_ZN5test38get_ab_2INS_7DerivedEEEDtptcvPT_Li0Esr5Path2E2abERS2_(
template <class T> decltype(((T*) 0)->Path2::ab) get_ab_2(T &ref) { return ref.Path2::ab; }
- // CHECK: define linkonce_odr float @_ZN5test37get_p_1INS_7DerivedEEEDtptcvPT_Li0EsrNS_5Path1E1pERS2_(
+ // CHECK: define linkonce_odr float @_ZN5test37get_p_1INS_7DerivedEEEDtptcvPT_Li0Esr5Path1E1pERS2_(
template <class T> decltype(((T*) 0)->Path1::p) get_p_1(T &ref) { return ref.Path1::p; }
- // CHECK: define linkonce_odr double @_ZN5test37get_p_2INS_7DerivedEEEDtptcvPT_Li0EsrNS_5Path2E1pERS2_(
+ // CHECK: define linkonce_odr double @_ZN5test37get_p_2INS_7DerivedEEEDtptcvPT_Li0Esr5Path2E1pERS2_(
template <class T> decltype(((T*) 0)->Path2::p) get_p_2(T &ref) { return ref.Path2::p; }
Derived obj;
@@ -676,3 +676,38 @@ namespace test25 {
A<foo>::call();
}
}
+
+namespace test26 {
+ template <template <class> class T> void foo(decltype(T<float>::object) &object) {}
+
+ template <class T> struct holder { static T object; };
+
+ void test() {
+ float f;
+
+ // CHECK: call void @_ZN6test263fooINS_6holderEEEvRDtsrT_IfE6objectE(
+ foo<holder>(f);
+ }
+}
+
+namespace test27 {
+ struct A {
+ struct inner {
+ float object;
+ };
+
+ float meth();
+ };
+ typedef A Alias;
+
+ template <class T> void a(decltype(T::inner::object) &object) {}
+ template <class T> void b(decltype(T().Alias::meth()) &object) {}
+
+ void test() {
+ float f;
+ // CHECK: call void @_ZN6test271aINS_1AEEEvRDtsrNT_5innerE6objectE(
+ a<A>(f);
+ // CHECK: call void @_ZN6test271bINS_1AEEEvRDTcldtcvT__Esr5AliasE4methEE(
+ b<A>(f);
+ }
+}
diff --git a/test/CodeGenCXX/member-init-ctor.cpp b/test/CodeGenCXX/member-init-ctor.cpp
new file mode 100644
index 0000000..d9a6734
--- /dev/null
+++ b/test/CodeGenCXX/member-init-ctor.cpp
@@ -0,0 +1,14 @@
+// RUN: %clang_cc1 %s -std=c++0x -emit-llvm -o - | FileCheck %s
+
+bool b();
+struct S {
+ int n = b() ? S().n + 1 : 0;
+};
+
+S s;
+
+// CHECK: define{{.*}} void @_ZN1SC2Ev(
+// CHECK-NOT }
+// CHECK: call {{.*}} @_Z1bv()
+// CHECK-NOT }
+// CHECK: call {{.*}} @_ZN1SC1Ev(
diff --git a/test/CodeGenCXX/new.cpp b/test/CodeGenCXX/new.cpp
index 10a6f7f..d14a5e2 100644
--- a/test/CodeGenCXX/new.cpp
+++ b/test/CodeGenCXX/new.cpp
@@ -1,12 +1,16 @@
// RUN: %clang_cc1 -triple x86_64-unknown-unknown %s -emit-llvm -o - | FileCheck %s
-#include <stddef.h>
+
+typedef __typeof__(sizeof(0)) size_t;
void t1() {
int* a = new int;
}
-// Placement.
-void* operator new(size_t, void*) throw();
+// Declare the reserved placement operators.
+void *operator new(size_t, void*) throw();
+void operator delete(void*, void*) throw();
+void *operator new[](size_t, void*) throw();
+void operator delete[](void*, void*) throw();
void t2(int* a) {
int* b = new (a) int;
@@ -163,3 +167,45 @@ void f() {
delete new bool;
// CHECK: ret void
}
+
+namespace test15 {
+ struct A { A(); ~A(); };
+
+ // CHECK: define void @_ZN6test155test0EPv(
+ // CHECK: [[P:%.*]] = load i8*
+ // CHECK-NEXT: icmp eq i8* [[P]], null
+ // CHECK-NEXT: br i1
+ // CHECK: [[T0:%.*]] = bitcast i8* [[P]] to [[A:%.*]]*
+ // CHECK-NEXT: call void @_ZN6test151AC1Ev([[A]]* [[T0]])
+ void test0(void *p) {
+ new (p) A();
+ }
+
+ // CHECK: define void @_ZN6test155test1EPv(
+ // CHECK: [[P:%.*]] = load i8*
+ // CHECK-NEXT: icmp eq i8* [[P]], null
+ // CHECK-NEXT: br i1
+ // CHECK: [[T0:%.*]] = bitcast i8* [[P]] to [[A:%.*]]*
+ // CHECK: [[T1:%.*]] = getelementptr inbounds [[A]]* [[T0]],
+ // CHECK-NEXT: call void @_ZN6test151AC1Ev([[A]]* [[T1]])
+ void test1(void *p) {
+ new (p) A[5];
+ }
+
+ // TODO: it's okay if all these size calculations get dropped.
+ // FIXME: maybe we should try to throw on overflow?
+ // CHECK: define void @_ZN6test155test2EPvi(
+ // CHECK: [[N:%.*]] = load i32*
+ // CHECK-NEXT: [[T0:%.*]] = sext i32 [[N]] to i64
+ // CHECK-NEXT: [[T1:%.*]] = icmp slt i64 [[T0]], 0
+ // CHECK-NEXT: [[T2:%.*]] = select i1 [[T1]], i64 -1, i64 [[T0]]
+ // CHECK-NEXT: [[P:%.*]] = load i8*
+ // CHECK-NEXT: icmp eq i8* [[P]], null
+ // CHECK-NEXT: br i1
+ // CHECK: [[T0:%.*]] = bitcast i8* [[P]] to [[A:%.*]]*
+ // CHECK: [[T1:%.*]] = getelementptr inbounds [[A]]* [[T0]],
+ // CHECK-NEXT: call void @_ZN6test151AC1Ev([[A]]* [[T1]])
+ void test2(void *p, int n) {
+ new (p) A[n];
+ }
+}
diff --git a/test/CodeGenCXX/nrvo.cpp b/test/CodeGenCXX/nrvo.cpp
index ad6fa4f..82caff8 100644
--- a/test/CodeGenCXX/nrvo.cpp
+++ b/test/CodeGenCXX/nrvo.cpp
@@ -95,7 +95,7 @@ X test2(bool B) {
// %invoke.cont17: rethrow block for %eh.cleanup.
// This really should be elsewhere in the function.
- // CHECK-EH: call void @_Unwind_Resume_or_Rethrow
+ // CHECK-EH: call void @llvm.eh.resume(
// CHECK-EH-NEXT: unreachable
// %terminate.lpad: terminate landing pad.
diff --git a/test/CodeGenCXX/pr9965.cpp b/test/CodeGenCXX/pr9965.cpp
new file mode 100644
index 0000000..b87fcf4
--- /dev/null
+++ b/test/CodeGenCXX/pr9965.cpp
@@ -0,0 +1,12 @@
+// RUN: %clang_cc1 -std=c++0x -emit-llvm -o - %s | FileCheck %s
+template<typename T>
+struct X
+{
+ X() = default;
+};
+
+X<int> x;
+// CHECK: define internal void @__cxx_global_var_init()
+// CHECK: call void @_ZN1XIiEC1Ev
+// CHECK: define linkonce_odr void @_ZN1XIiEC1Ev
+// CHECK: define linkonce_odr void @_ZN1XIiEC2Ev
diff --git a/test/CodeGenCXX/ptr-to-member-function.cpp b/test/CodeGenCXX/ptr-to-member-function.cpp
index 89db142..d012fb9 100644
--- a/test/CodeGenCXX/ptr-to-member-function.cpp
+++ b/test/CodeGenCXX/ptr-to-member-function.cpp
@@ -1,3 +1,4 @@
+// REQUIRES: x86-registered-target,x86-64-registered-target
// RUN: %clang_cc1 -triple x86_64-apple-darwin -std=c++0x -S %s -o %t-64.s
// RUN: FileCheck -check-prefix LP64 --input-file=%t-64.s %s
// RUN: %clang_cc1 -triple i386-apple-darwin -std=c++0x -S %s -o %t-32.s
diff --git a/test/CodeGenCXX/scoped-enums.cpp b/test/CodeGenCXX/scoped-enums.cpp
new file mode 100644
index 0000000..d40ab36
--- /dev/null
+++ b/test/CodeGenCXX/scoped-enums.cpp
@@ -0,0 +1,9 @@
+// RUN: %clang_cc1 -std=c++0x -emit-llvm -o - %s
+
+// PR9923
+enum class Color { red, blue, green };
+
+void f(Color);
+void g() {
+ f(Color::red);
+}
diff --git a/test/CodeGenCXX/skip-vtable-pointer-initialization.cpp b/test/CodeGenCXX/skip-vtable-pointer-initialization.cpp
new file mode 100644
index 0000000..84697be
--- /dev/null
+++ b/test/CodeGenCXX/skip-vtable-pointer-initialization.cpp
@@ -0,0 +1,200 @@
+// RUN: %clang_cc1 %s -triple=x86_64-apple-darwin10 -emit-llvm -o - | FileCheck %s
+
+// See Test9 for test description.
+// CHECK: @_ZTTN5Test91BE = linkonce_odr unnamed_addr constant
+namespace Test1 {
+
+// Check that we don't initialize the vtable pointer in A::~A(), since the destructor body is trivial.
+struct A {
+ virtual void f();
+ ~A();
+};
+
+// CHECK: define void @_ZN5Test11AD2Ev
+// CHECK-NOT: store i8** getelementptr inbounds ([3 x i8*]* @_ZTVN5Test11AE, i64 0, i64 2), i8***
+A::~A()
+{
+}
+
+}
+
+namespace Test2 {
+
+// Check that we do initialize the vtable pointer in A::~A() since the destructor body isn't trivial.
+struct A {
+ virtual void f();
+ ~A();
+};
+
+// CHECK: define void @_ZN5Test21AD2Ev
+// CHECK: store i8** getelementptr inbounds ([3 x i8*]* @_ZTVN5Test21AE, i64 0, i64 2), i8***
+A::~A() {
+ f();
+}
+
+}
+
+namespace Test3 {
+
+// Check that we don't initialize the vtable pointer in A::~A(), since the destructor body is trivial
+// and Field's destructor body is also trivial.
+struct Field {
+ ~Field() { }
+};
+
+struct A {
+ virtual void f();
+ ~A();
+
+ Field field;
+};
+
+// CHECK: define void @_ZN5Test31AD2Ev
+// CHECK-NOT: store i8** getelementptr inbounds ([3 x i8*]* @_ZTVN5Test31AE, i64 0, i64 2), i8***
+A::~A() {
+
+}
+
+}
+
+namespace Test4 {
+
+// Check that we do initialize the vtable pointer in A::~A(), since Field's destructor body
+// isn't trivial.
+
+void f();
+
+struct Field {
+ ~Field() { f(); }
+};
+
+struct A {
+ virtual void f();
+ ~A();
+
+ Field field;
+};
+
+// CHECK: define void @_ZN5Test41AD2Ev
+// CHECK: store i8** getelementptr inbounds ([3 x i8*]* @_ZTVN5Test41AE, i64 0, i64 2), i8***
+A::~A()
+{
+}
+
+}
+
+namespace Test5 {
+
+// Check that we do initialize the vtable pointer in A::~A(), since Field's destructor isn't
+// available in this translation unit.
+
+struct Field {
+ ~Field();
+};
+
+struct A {
+ virtual void f();
+ ~A();
+
+ Field field;
+};
+
+// CHECK: define void @_ZN5Test51AD2Ev
+// CHECK: store i8** getelementptr inbounds ([3 x i8*]* @_ZTVN5Test51AE, i64 0, i64 2), i8***
+A::~A()
+{
+}
+
+}
+
+namespace Test6 {
+
+// Check that we do initialize the vtable pointer in A::~A(), since Field has a member
+// variable with a non-trivial destructor body.
+
+struct NonTrivialDestructorBody {
+ ~NonTrivialDestructorBody();
+};
+
+struct Field {
+ NonTrivialDestructorBody nonTrivialDestructorBody;
+};
+
+struct A {
+ virtual void f();
+ ~A();
+
+ Field field;
+};
+
+// CHECK: define void @_ZN5Test61AD2Ev
+// CHECK: store i8** getelementptr inbounds ([3 x i8*]* @_ZTVN5Test61AE, i64 0, i64 2), i8***
+A::~A()
+{
+}
+
+}
+
+namespace Test7 {
+
+// Check that we do initialize the vtable pointer in A::~A(), since Field has a base
+// class with a non-trivial destructor body.
+
+struct NonTrivialDestructorBody {
+ ~NonTrivialDestructorBody();
+};
+
+struct Field : NonTrivialDestructorBody { };
+
+struct A {
+ virtual void f();
+ ~A();
+
+ Field field;
+};
+
+// CHECK: define void @_ZN5Test71AD2Ev
+// CHECK: store i8** getelementptr inbounds ([3 x i8*]* @_ZTVN5Test71AE, i64 0, i64 2), i8***
+A::~A()
+{
+}
+
+}
+
+namespace Test8 {
+
+// Check that we do initialize the vtable pointer in A::~A(), since Field has a virtual base
+// class with a non-trivial destructor body.
+
+struct NonTrivialDestructorBody {
+ ~NonTrivialDestructorBody();
+};
+
+struct Field : virtual NonTrivialDestructorBody { };
+
+struct A {
+ virtual void f();
+ ~A();
+
+ Field field;
+};
+
+// CHECK: define void @_ZN5Test81AD2Ev
+// CHECK: store i8** getelementptr inbounds ([3 x i8*]* @_ZTVN5Test81AE, i64 0, i64 2), i8***
+A::~A()
+{
+}
+
+}
+
+namespace Test9 {
+
+// Check that we emit a VTT for B, even though we don't initialize the vtable pointer in the destructor.
+struct A { virtual ~A () { } };
+struct B : virtual A {};
+struct C : virtual B {
+ virtual ~C();
+};
+C::~C() {}
+
+}
diff --git a/test/CodeGenCXX/static-init-2.cpp b/test/CodeGenCXX/static-init-2.cpp
index 65ab3bb..768e6de 100644
--- a/test/CodeGenCXX/static-init-2.cpp
+++ b/test/CodeGenCXX/static-init-2.cpp
@@ -3,4 +3,4 @@
// Make sure we don't crash generating y; its value is constant, but the
// initializer has side effects, so EmitConstantExpr should fail.
int x();
-int y = x() && 0;
+int y = x() & 0;
diff --git a/test/CodeGenCXX/template-instantiation.cpp b/test/CodeGenCXX/template-instantiation.cpp
index 635e1d2..cc30af0 100644
--- a/test/CodeGenCXX/template-instantiation.cpp
+++ b/test/CodeGenCXX/template-instantiation.cpp
@@ -1,9 +1,15 @@
// RUN: %clang_cc1 %s -O1 -triple=x86_64-apple-darwin10 -emit-llvm -o - | FileCheck %s
+// CHECK: @_ZN7PR100011xE = global
+// CHECK-NOT: @_ZN7PR100014kBarE = external global i32
+//
// CHECK-NOT: @_ZTVN5test118stdio_sync_filebufIwEE = constant
// CHECK-NOT: _ZTVN5test315basic_fstreamXXIcEE
// CHECK: @_ZTVN5test018stdio_sync_filebufIwEE = unnamed_addr constant
+// CHECK: @_ZN7PR100011SIiE3arrE = weak_odr global [3 x i32]
+// CHECK-NOT: @_ZN7PR100011SIiE3arr2E = weak_odr global [3 x i32]A
+
// CHECK-NOT: _ZTVN5test31SIiEE
// CHECK-NOT: _ZTSN5test31SIiEE
@@ -122,3 +128,27 @@ class B {
// CHECK-NOT: _ZN6PR85051AILi0EE1B1fEv
template class A<0>;
}
+
+// Ensure that when instantiating initializers for static data members to
+// complete their type in an unevaluated context, we *do* emit initializers with
+// side-effects, but *don't* emit initializers and variables which are otherwise
+// unused in the program.
+namespace PR10001 {
+ template <typename T> struct S {
+ static const int arr[];
+ static const int arr2[];
+ static const int x, y;
+ static int f();
+ };
+
+ extern int foo();
+ extern int kBar;
+
+ template <typename T> const int S<T>::arr[] = { 1, 2, foo() }; // possible side effects
+ template <typename T> const int S<T>::arr2[] = { 1, 2, kBar }; // no side effects
+ template <typename T> const int S<T>::x = sizeof(arr) / sizeof(arr[0]);
+ template <typename T> const int S<T>::y = sizeof(arr2) / sizeof(arr2[0]);
+ template <typename T> int S<T>::f() { return x + y; }
+
+ int x = S<int>::f();
+}
diff --git a/test/CodeGenCXX/threadsafe-statics-exceptions.cpp b/test/CodeGenCXX/threadsafe-statics-exceptions.cpp
index 0bd810e..aa79a4f 100644
--- a/test/CodeGenCXX/threadsafe-statics-exceptions.cpp
+++ b/test/CodeGenCXX/threadsafe-statics-exceptions.cpp
@@ -24,6 +24,6 @@ void f() {
// 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: call void @llvm.eh.resume(
// CHECK: unreachable
}
diff --git a/test/CodeGenCXX/thunks.cpp b/test/CodeGenCXX/thunks.cpp
index a74cc05..7c80b96 100644
--- a/test/CodeGenCXX/thunks.cpp
+++ b/test/CodeGenCXX/thunks.cpp
@@ -265,18 +265,42 @@ namespace Test11 {
struct C : B { virtual C* f(); };
C* C::f() { return 0; }
+ // C::f itself.
+ // CHECK: define {{.*}} @_ZN6Test111C1fEv(
+
// The this-adjustment and return-adjustment thunk required when
// C::f appears in a vtable where A is at a nonzero offset from C.
// CHECK: define {{.*}} @_ZTcv0_n24_v0_n32_N6Test111C1fEv(
- // C::f itself.
- // CHECK: define {{.*}} @_ZN6Test111C1fEv(
-
// The return-adjustment thunk required when C::f appears in a vtable
// where A is at a zero offset from C.
// CHECK: define {{.*}} @_ZTch0_v0_n32_N6Test111C1fEv(
}
+// Varargs thunk test.
+namespace Test12 {
+ struct A {
+ virtual A* f(int x, ...);
+ };
+ struct B {
+ virtual B* f(int x, ...);
+ };
+ struct C : A, B {
+ virtual void c();
+ virtual C* f(int x, ...);
+ };
+ C* C::f(int x, ...) { return this; }
+
+ // C::f
+ // CHECK: define {{.*}} @_ZN6Test121C1fEiz
+
+ // Varargs thunk; check that both the this and covariant adjustments
+ // are generated.
+ // CHECK: define {{.*}} @_ZTchn8_h8_N6Test121C1fEiz
+ // CHECK: getelementptr inbounds i8* {{.*}}, i64 -8
+ // CHECK: getelementptr inbounds i8* {{.*}}, i64 8
+}
+
/**** The following has to go at the end of the file ****/
// This is from Test5:
diff --git a/test/CodeGenCXX/vararg-non-pod.cpp b/test/CodeGenCXX/vararg-non-pod.cpp
new file mode 100644
index 0000000..6c6f459
--- /dev/null
+++ b/test/CodeGenCXX/vararg-non-pod.cpp
@@ -0,0 +1,16 @@
+// RUN: %clang_cc1 -Wno-error=non-pod-varargs -emit-llvm -o - %s | FileCheck %s
+
+struct X {
+ X();
+ X(const X&);
+ ~X();
+};
+
+void vararg(...);
+
+// CHECK: define void @_Z4test1X
+void test(X x) {
+ // CHECK: call void @llvm.trap()
+ vararg(x);
+ // CHECK: ret void
+}
diff --git a/test/CodeGenCXX/virtual-base-destructor-call.cpp b/test/CodeGenCXX/virtual-base-destructor-call.cpp
index 807eaff..f028e4c 100644
--- a/test/CodeGenCXX/virtual-base-destructor-call.cpp
+++ b/test/CodeGenCXX/virtual-base-destructor-call.cpp
@@ -27,11 +27,6 @@ int main() {
// CHECK: call void @_ZN13basic_istreamIcED2Ev
// CHECK: }
-// basic_istream's base dtor is a no-op.
-// CHECK: define linkonce_odr void @_ZN13basic_istreamIcED2Ev(%struct.basic_istream* %this, i8** %vtt) unnamed_addr
-// CHECK-NOT: call
-// CHECK: }
-
// basic_iostream's deleting dtor calls its complete dtor, then
// operator delete().
// CHECK: define linkonce_odr void @_ZN14basic_iostreamIcED0Ev(%struct.basic_iostream* %this) unnamed_addr
@@ -49,3 +44,8 @@ int main() {
// CHECK: define linkonce_odr void @_ZN13basic_istreamIcED0Ev(%struct.basic_istream* %this) unnamed_addr
// CHECK: call void @_ZN13basic_istreamIcED1Ev
// CHECK: call void @_ZdlPv
+
+// basic_istream's base dtor is a no-op.
+// CHECK: define linkonce_odr void @_ZN13basic_istreamIcED2Ev(%struct.basic_istream* %this, i8** %vtt) unnamed_addr
+// CHECK-NOT: call
+// CHECK: }
diff --git a/test/CodeGenCXX/x86_32-arguments.cpp b/test/CodeGenCXX/x86_32-arguments.cpp
index e94e2ca..4c06033 100644
--- a/test/CodeGenCXX/x86_32-arguments.cpp
+++ b/test/CodeGenCXX/x86_32-arguments.cpp
@@ -31,7 +31,7 @@ void f(C) { }
// CHECK: define void @_ZThn4_N18BasicAliasAnalysis13getModRefInfoE8CallSite
// ...
-// CHECK: %struct.CallSite* byval %CS)
+// CHECK: %struct.CallSite* byval align 4 %CS)
struct CallSite {
unsigned Ptr;
CallSite(unsigned XX) : Ptr(XX) {}
@@ -89,7 +89,7 @@ struct s5 { s5(); int &x; };
s5 f5() { return s5(); }
// CHECK: define i32 @_Z4f6_0M2s6i(i32 %a)
-// CHECK: define i64 @_Z4f6_1M2s6FivE(%{{.*}} byval)
+// CHECK: define i64 @_Z4f6_1M2s6FivE(%{{.*}} byval align 4)
// FIXME: It would be nice to avoid byval on the previous case.
struct s6 {};
typedef int s6::* s6_mdp;
diff --git a/test/CodeGenObjC/bitfield-ivar-offsets.m b/test/CodeGenObjC/bitfield-ivar-offsets.m
index e0eebe1..ce6f17b 100644
--- a/test/CodeGenObjC/bitfield-ivar-offsets.m
+++ b/test/CodeGenObjC/bitfield-ivar-offsets.m
@@ -1,12 +1,12 @@
// RUNX: llvm-gcc -m64 -emit-llvm -S -o %t %s &&
// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fobjc-nonfragile-abi -emit-llvm -o %t %s
-// RUN: grep -F '@"OBJC_IVAR_$_I0._b0" = global i64 0, section "__DATA, __objc_const", align 8' %t
-// RUN: grep -F '@"OBJC_IVAR_$_I0._b1" = global i64 0, section "__DATA, __objc_const", align 8' %t
-// RUN: grep -F '@"OBJC_IVAR_$_I0._b2" = global i64 1, section "__DATA, __objc_const", align 8' %t
-// RUN: grep -F '@"OBJC_IVAR_$_I0._x" = global i64 2, section "__DATA, __objc_const", align 8' %t
-// RUN: grep -F '@"OBJC_IVAR_$_I0._b3" = global i64 4, section "__DATA, __objc_const", align 8' %t
-// RUN: grep -F '@"OBJC_IVAR_$_I0._y" = global i64 6, section "__DATA, __objc_const", align 8' %t
-// RUN: grep -F '@"OBJC_IVAR_$_I0._b4" = global i64 7, section "__DATA, __objc_const", align 8' %t
+// RUN: grep -F '@"OBJC_IVAR_$_I0._b0" = global i64 0, section "__DATA, __objc_ivar", align 8' %t
+// RUN: grep -F '@"OBJC_IVAR_$_I0._b1" = global i64 0, section "__DATA, __objc_ivar", align 8' %t
+// RUN: grep -F '@"OBJC_IVAR_$_I0._b2" = global i64 1, section "__DATA, __objc_ivar", align 8' %t
+// RUN: grep -F '@"OBJC_IVAR_$_I0._x" = global i64 2, section "__DATA, __objc_ivar", align 8' %t
+// RUN: grep -F '@"OBJC_IVAR_$_I0._b3" = global i64 4, section "__DATA, __objc_ivar", align 8' %t
+// RUN: grep -F '@"OBJC_IVAR_$_I0._y" = global i64 6, section "__DATA, __objc_ivar", align 8' %t
+// RUN: grep -F '@"OBJC_IVAR_$_I0._b4" = global i64 7, section "__DATA, __objc_ivar", align 8' %t
// RUN: grep -F '@"OBJC_IVAR_$_I0." = global' %t | count 0
@interface I0 {
diff --git a/test/CodeGenObjC/blocks-2.m b/test/CodeGenObjC/blocks-2.m
index 38b8635..5d63e91 100644
--- a/test/CodeGenObjC/blocks-2.m
+++ b/test/CodeGenObjC/blocks-2.m
@@ -33,5 +33,5 @@ void test1() {
// CHECK: call i8* @llvm.eh.exception()
// CHECK: [[T1:%.*]] = bitcast [[N_T]]* [[N]] to i8*
// CHECK-NEXT: call void @_Block_object_dispose(i8* [[T1]], i32 8)
- // CHECK: call void @_Unwind_Resume_or_Rethrow(
+ // CHECK: call void @llvm.eh.resume(
}
diff --git a/test/CodeGenObjC/constant-string-class-1.m b/test/CodeGenObjC/constant-string-class-1.m
new file mode 100644
index 0000000..8ff605e
--- /dev/null
+++ b/test/CodeGenObjC/constant-string-class-1.m
@@ -0,0 +1,23 @@
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fobjc-nonfragile-abi -fno-constant-cfstrings -fconstant-string-class OFConstantString -emit-llvm -o %t %s
+// pr9914
+
+@interface OFConstantString
++ class;
+@end
+
+@interface OFString
+- (void)XMLElementBySerializing;
+@end
+
+@implementation OFString
+
+- (void)XMLElementBySerializing
+{
+ id str = @"object";
+
+ [OFConstantString class];
+}
+
+@end
+
+// CHECK: @"OBJC_CLASS_$_OFConstantString" = external global
diff --git a/test/CodeGenObjC/constant-string-class.m b/test/CodeGenObjC/constant-string-class.m
index 12253d6..489f511 100644
--- a/test/CodeGenObjC/constant-string-class.m
+++ b/test/CodeGenObjC/constant-string-class.m
@@ -32,4 +32,4 @@ int main () {
// CHECK-FRAGILE: @_FooClassReference = common global
// CHECK-NONFRAGILE: @"OBJC_CLASS_$_Object" = external global
-// CHECK-NONFRAGILE: "OBJC_CLASS_$_Foo" = unnamed_addr global
+// CHECK-NONFRAGILE: "OBJC_CLASS_$_Foo" = global
diff --git a/test/CodeGenObjC/debug-info-block-helper.m b/test/CodeGenObjC/debug-info-block-helper.m
new file mode 100644
index 0000000..136af14
--- /dev/null
+++ b/test/CodeGenObjC/debug-info-block-helper.m
@@ -0,0 +1,30 @@
+// REQUIRES: x86-64-registered-target
+// RUN: %clang_cc1 -masm-verbose -S -fblocks -g -triple x86_64-apple-darwin10 %s -o - | FileCheck %s
+extern void foo(void(^)(void));
+
+// CHECK: .ascii "__destroy_helper_block_" ## DW_AT_name
+
+@interface NSObject {
+ struct objc_object *isa;
+}
+@end
+
+@interface A:NSObject @end
+@implementation A
+- (void) helper {
+ int master = 0;
+ __block int m2 = 0;
+ __block int dbTransaction = 0;
+ int (^x)(void) = ^(void) { (void) self;
+ (void) master;
+ (void) dbTransaction;
+ m2++;
+ return m2;
+
+ };
+ master = x();
+}
+@end
+
+void foo(void(^x)(void)) {}
+
diff --git a/test/CodeGenObjC/debug-info-blocks.m b/test/CodeGenObjC/debug-info-blocks.m
new file mode 100644
index 0000000..fc8e962
--- /dev/null
+++ b/test/CodeGenObjC/debug-info-blocks.m
@@ -0,0 +1,55 @@
+// REQUIRES: x86-64-registered-target
+// RUN: %clang_cc1 -masm-verbose -S -fblocks -g -triple x86_64-apple-darwin10 -fobjc-nonfragile-abi -fobjc-dispatch-method=mixed %s -o - | FileCheck %s
+
+//Radar 9279956
+//CHECK: ## DW_OP_deref
+//CHECK-NEXT: ## DW_OP_plus_uconst
+
+typedef unsigned int NSUInteger;
+
+@protocol NSObject
+@end
+
+@interface NSObject <NSObject>
+- (id)init;
++ (id)alloc;
+@end
+
+@interface NSDictionary : NSObject
+- (NSUInteger)count;
+@end
+
+@interface NSMutableDictionary : NSDictionary
+@end
+
+@interface A : NSObject {
+@public
+ int ivar;
+}
+@end
+
+static void run(void (^block)(void))
+{
+ block();
+}
+
+@implementation A
+
+- (id)init
+{
+ if ((self = [super init])) {
+ run(^{
+ NSMutableDictionary *d = [[NSMutableDictionary alloc] init];
+ ivar = 42 + (int)[d count];
+ });
+ }
+ return self;
+}
+
+@end
+
+int main()
+{
+ A *a = [[A alloc] init];
+ return 0;
+}
diff --git a/test/CodeGenObjC/debug-info-class-extension.m b/test/CodeGenObjC/debug-info-class-extension.m
new file mode 100644
index 0000000..cf0445d
--- /dev/null
+++ b/test/CodeGenObjC/debug-info-class-extension.m
@@ -0,0 +1,15 @@
+// RUN: %clang_cc1 -fobjc-nonfragile-abi -masm-verbose -S -g %s -o - | FileCheck %s
+
+// CHECK: AT_APPLE_objc_complete_type
+
+@interface I1
+@end
+
+@implementation I1 {
+int myi2;
+}
+int myi;
+@end
+
+void foo(I1 *iptr) {}
+
diff --git a/test/CodeGenObjC/debug-info-class-extension2.m b/test/CodeGenObjC/debug-info-class-extension2.m
new file mode 100644
index 0000000..4cef88f
--- /dev/null
+++ b/test/CodeGenObjC/debug-info-class-extension2.m
@@ -0,0 +1,14 @@
+// RUN: %clang_cc1 -fobjc-nonfragile-abi -masm-verbose -S -g %s -o - | FileCheck %s
+// CHECK: AT_APPLE_objc_complete_type
+
+@interface Foo {} @end
+
+@interface Foo () {
+ int *bar;
+}
+@end
+
+@implementation Foo
+@end
+
+void bar(Foo *fptr) {}
diff --git a/test/CodeGenObjC/debug-info-class-extension3.m b/test/CodeGenObjC/debug-info-class-extension3.m
new file mode 100644
index 0000000..595c7bd
--- /dev/null
+++ b/test/CodeGenObjC/debug-info-class-extension3.m
@@ -0,0 +1,12 @@
+// RUN: %clang_cc1 -fobjc-nonfragile-abi -masm-verbose -S -g %s -o - | FileCheck %s
+
+// CHECK-NOT: AT_APPLE_objc_complete_type
+
+@interface Foo {} @end
+
+@interface Foo () {
+ int *bar;
+}
+@end
+
+void bar(Foo *fptr) {}
diff --git a/test/CodeGenObjC/debug-info-crash.m b/test/CodeGenObjC/debug-info-crash.m
index 92f9c0e..eb2143f 100644
--- a/test/CodeGenObjC/debug-info-crash.m
+++ b/test/CodeGenObjC/debug-info-crash.m
@@ -1,3 +1,4 @@
+// REQUIRES: x86-registered-target
// RUN: %clang_cc1 -triple i386-apple-darwin10 -fblocks -g -S %s -o -
// rdar://7556129
diff --git a/test/CodeGenObjC/debug-info-getter-name.m b/test/CodeGenObjC/debug-info-getter-name.m
index 746fcee..ec784e3 100644
--- a/test/CodeGenObjC/debug-info-getter-name.m
+++ b/test/CodeGenObjC/debug-info-getter-name.m
@@ -1,3 +1,4 @@
+// REQUIRES: x86-64-registered-target
// RUN: %clang_cc1 -fno-dwarf2-cfi-asm -triple x86_64-apple-darwin10 -fobjc-nonfragile-abi -S -g %s -o - | FileCheck %s
//CHECK: "-[InstanceVariablesEverywhereButTheInterface someString]":
@@ -43,6 +44,8 @@
@end
@implementation AutomaticSynthesis
+@synthesize someString;
+@synthesize someNumber;
- init
{
return self;
diff --git a/test/CodeGenObjC/debug-info-pubtypes.m b/test/CodeGenObjC/debug-info-pubtypes.m
new file mode 100644
index 0000000..744a366
--- /dev/null
+++ b/test/CodeGenObjC/debug-info-pubtypes.m
@@ -0,0 +1,19 @@
+// REQUIRES: x86-64-registered-target
+// RUN: %clang -cc1 -triple x86_64-apple-darwin10 -g -S %s -o %t
+// RUN: FileCheck %s < %t
+
+//CHECK: .long Lset6
+//CHECK-NEXT: .long
+//CHECK-NEXT: .asciz "H"
+//CHECK-NEXT: .long 0
+//CHECK-NEXT: Lpubtypes_end1:
+
+@interface H
+-(void) foo;
+@end
+
+@implementation H
+-(void) foo {
+}
+@end
+
diff --git a/test/CodeGenObjC/debug-info-static-var.m b/test/CodeGenObjC/debug-info-static-var.m
index 3bcf5fd..94513f2 100644
--- a/test/CodeGenObjC/debug-info-static-var.m
+++ b/test/CodeGenObjC/debug-info-static-var.m
@@ -1,3 +1,4 @@
+// REQUIRES: x86-64-registered-target
// RUN: %clang_cc1 -g -triple x86_64-apple-darwin10 -S -masm-verbose -o - %s | FileCheck %s
// Radar 8801045
// Do not emit AT_MIPS_linkage_name for static variable i
diff --git a/test/CodeGenObjC/debug-property-synth.m b/test/CodeGenObjC/debug-property-synth.m
new file mode 100644
index 0000000..05852b7
--- /dev/null
+++ b/test/CodeGenObjC/debug-property-synth.m
@@ -0,0 +1,19 @@
+// RUN: %clang_cc1 -masm-verbose -S -g %s -o - | FileCheck %s
+// Radar 9468526
+@interface I {
+ int _p1;
+}
+@property int p1;
+@end
+
+@implementation I
+@synthesize p1 = _p1;
+@end
+
+int main() {
+ I *myi;
+ myi.p1 = 2;
+ return 0;
+}
+
+// CHECK: .loc 2 10 0
diff --git a/test/CodeGenObjC/encode-test.m b/test/CodeGenObjC/encode-test.m
index 24a90a0..ade0c61 100644
--- a/test/CodeGenObjC/encode-test.m
+++ b/test/CodeGenObjC/encode-test.m
@@ -144,3 +144,20 @@ struct s8 {
long double x;
};
const char g8[] = @encode(struct s8);
+
+// CHECK: @g9 = constant [11 x i8] c"{S9=i[0i]}\00"
+struct S9 {
+ int x;
+ int flex[];
+};
+const char g9[] = @encode(struct S9);
+
+struct f
+{
+ int i;
+ struct{} g[4];
+ int tt;
+};
+
+// CHECK: @g10 = constant [14 x i8] c"{f=i[0{?=}]i}\00"
+const char g10[] = @encode(struct f);
diff --git a/test/CodeGenObjC/forward-decl-param.m b/test/CodeGenObjC/forward-decl-param.m
new file mode 100644
index 0000000..d54a888
--- /dev/null
+++ b/test/CodeGenObjC/forward-decl-param.m
@@ -0,0 +1,19 @@
+// RUN: %clang_cc1 %s -emit-llvm -o -
+
+// <rdar://problem/9123036> crash due to forward-declared struct in
+// protocol method parameter.
+
+@protocol P
+- (void) A:(struct z) z;
+@end
+@interface I < P >
+@end
+@implementation I
+@end
+
+@interface I2
+- (void) A:(struct z2) z2;
+@end
+@implementation I2
+@end
+
diff --git a/test/CodeGenObjC/instance-method-metadata.m b/test/CodeGenObjC/instance-method-metadata.m
index ae87c7a..4e752c0 100644
--- a/test/CodeGenObjC/instance-method-metadata.m
+++ b/test/CodeGenObjC/instance-method-metadata.m
@@ -1,3 +1,4 @@
+// REQUIRES: x86-64-registered-target
// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fobjc-nonfragile-abi -S -o %t %s
// RUN: FileCheck < %t %s
diff --git a/test/CodeGenObjC/interface-layout-64.m b/test/CodeGenObjC/interface-layout-64.m
index af898bb..5158c61 100644
--- a/test/CodeGenObjC/interface-layout-64.m
+++ b/test/CodeGenObjC/interface-layout-64.m
@@ -1,17 +1,17 @@
// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fobjc-nonfragile-abi -emit-llvm -o %t %s
// RUNX: llvm-gcc -m64 -emit-llvm -S -o %t %s &&
-// RUN: grep '@"OBJC_IVAR_$_I3._iv2" = global i64 8, section "__DATA, __objc_const", align 8' %t
-// RUN: grep '@"OBJC_IVAR_$_I3._iv3" = global i64 12, section "__DATA, __objc_const", align 8' %t
-// RUN: grep '@"OBJC_IVAR_$_I4._iv4" = global i64 13, section "__DATA, __objc_const", align 8' %t
-// RUN: grep '@"OBJC_IVAR_$_I5._iv5" = global i64 14, section "__DATA, __objc_const", align 8' %t
-// RUN: grep '@"OBJC_IVAR_$_I5._iv6_synth" = hidden global i64 16, section "__DATA, __objc_const", align 8' %t
-// RUN: grep '@"OBJC_IVAR_$_I5._iv7_synth" = hidden global i64 20, section "__DATA, __objc_const", align 8' %t
-// RUN: grep '@"OBJC_IVAR_$_I6.iv0" = global i64 0, section "__DATA, __objc_const", align 8' %t
-// RUN: grep '@"OBJC_IVAR_$_I8.b" = global i64 8, section "__DATA, __objc_const", align 8' %t
-// RUN: grep '@"OBJC_IVAR_$_I9.iv0" = global i64 0, section "__DATA, __objc_const", align 8' %t
-// RUN: grep '@"OBJC_IVAR_$_I10.iv1" = global i64 4, section "__DATA, __objc_const", align 8' %t
-// RUN: grep '@"OBJC_IVAR_$_I12.iv2" = global i64 8, section "__DATA, __objc_const", align 8' %t
+// RUN: grep '@"OBJC_IVAR_$_I3._iv2" = global i64 8, section "__DATA, __objc_ivar", align 8' %t
+// RUN: grep '@"OBJC_IVAR_$_I3._iv3" = global i64 12, section "__DATA, __objc_ivar", align 8' %t
+// RUN: grep '@"OBJC_IVAR_$_I4._iv4" = global i64 13, section "__DATA, __objc_ivar", align 8' %t
+// RUN: grep '@"OBJC_IVAR_$_I5._iv5" = global i64 14, section "__DATA, __objc_ivar", align 8' %t
+// RUN: grep '@"OBJC_IVAR_$_I5._iv6_synth" = hidden global i64 16, section "__DATA, __objc_ivar", align 8' %t
+// RUN: grep '@"OBJC_IVAR_$_I5._iv7_synth" = hidden global i64 20, section "__DATA, __objc_ivar", align 8' %t
+// RUN: grep '@"OBJC_IVAR_$_I6.iv0" = global i64 0, section "__DATA, __objc_ivar", align 8' %t
+// RUN: grep '@"OBJC_IVAR_$_I8.b" = global i64 8, section "__DATA, __objc_ivar", align 8' %t
+// RUN: grep '@"OBJC_IVAR_$_I9.iv0" = global i64 0, section "__DATA, __objc_ivar", align 8' %t
+// RUN: grep '@"OBJC_IVAR_$_I10.iv1" = global i64 4, section "__DATA, __objc_ivar", align 8' %t
+// RUN: grep '@"OBJC_IVAR_$_I12.iv2" = global i64 8, section "__DATA, __objc_ivar", align 8' %t
// RUN: grep '_OBJC_CLASS_RO_$_I3" = internal global .* { i32 0, i32 8, i32 13, .*' %t
// RUN: grep '_OBJC_CLASS_RO_$_I4" = internal global .* { i32 0, i32 13, i32 14, .*' %t
// RUN: grep '_OBJC_CLASS_RO_$_I5" = internal global .* { i32 0, i32 14, i32 24, .*' %t
diff --git a/test/CodeGenObjC/ivar-layout-array0-struct.m b/test/CodeGenObjC/ivar-layout-array0-struct.m
index 4300db3..a9ae0ac 100644
--- a/test/CodeGenObjC/ivar-layout-array0-struct.m
+++ b/test/CodeGenObjC/ivar-layout-array0-struct.m
@@ -1,3 +1,4 @@
+// REQUIRES: x86-64-registered-target
// 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
diff --git a/test/CodeGenObjC/ivar-layout-no-optimize.m b/test/CodeGenObjC/ivar-layout-no-optimize.m
index 7760f94..2851e79 100644
--- a/test/CodeGenObjC/ivar-layout-no-optimize.m
+++ b/test/CodeGenObjC/ivar-layout-no-optimize.m
@@ -1,3 +1,4 @@
+// REQUIRES: x86-64-registered-target
// 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
diff --git a/test/CodeGenObjC/messages-2.m b/test/CodeGenObjC/messages-2.m
index 5ef2261..e4e8cfb 100644
--- a/test/CodeGenObjC/messages-2.m
+++ b/test/CodeGenObjC/messages-2.m
@@ -147,17 +147,29 @@ typedef struct {
// rdar://problem/7854674
// CHECK: define void @test0([[A:%.*]]*
// CHECK-NF: define void @test0([[A:%.*]]*
-void test0(A *a) {
- // CHECK: alloca [[A]]*
+void test0(A *x) {
+ // CHECK: [[X:%.*]] = alloca [[A]]*
// CHECK-NEXT: [[POINT:%.*]] = alloca [[POINT_T:%.*]],
- // CHECK-NF: alloca [[A]]*
- // CHECK-NF-NEXT: [[POINT:%.*]] = alloca [[POINT_T:%.*]],
-
+ // CHECK: [[T0:%.*]] = load [[A]]** [[X]]
+ // CHECK: [[T1:%.*]] = bitcast [[A]]* [[T0]] to i8*
+ // CHECK-NEXT: icmp eq i8* [[T1]], null
+ // CHECK-NEXT: br i1
+ // CHECK: call {{.*}} @objc_msgSend_stret to
+ // CHECK-NEXT: br label
// CHECK: [[T0:%.*]] = bitcast [[POINT_T]]* [[POINT]] to i8*
// CHECK-NEXT: call void @llvm.memset.p0i8.i64(i8* [[T0]], i8 0, i64 48, i32 4, i1 false)
- // CHECK-NEXT: call {{.*}} @objc_msgSend_stret to
+ // CHECK-NEXT: br label
+
+ // CHECK-NF: [[X:%.*]] = alloca [[A]]*
+ // CHECK-NF-NEXT: [[POINT:%.*]] = alloca [[POINT_T:%.*]],
+ // CHECK-NF: [[T0:%.*]] = load [[A]]** [[X]]
+ // CHECK-NF: [[T1:%.*]] = bitcast [[A]]* [[T0]] to i8*
+ // CHECK-NF-NEXT: icmp eq i8* [[T1]], null
+ // CHECK-NF-NEXT: br i1
+ // CHECK-NF: call {{.*}} @objc_msgSend_stret to
+ // CHECK-NF-NEXT: br label
// CHECK-NF: [[T0:%.*]] = bitcast [[POINT_T]]* [[POINT]] to i8*
// CHECK-NF-NEXT: call void @llvm.memset.p0i8.i64(i8* [[T0]], i8 0, i64 48, i32 4, i1 false)
- // CHECK-NF-NEXT: call {{.*}} @objc_msgSend_stret to
- MyPoint point = [a returnAPoint];
+ // CHECK-NF-NEXT: br label
+ MyPoint point = [x returnAPoint];
}
diff --git a/test/CodeGenObjC/metadata-symbols-64.m b/test/CodeGenObjC/metadata-symbols-64.m
index 908c95c..4bc41fa 100644
--- a/test/CodeGenObjC/metadata-symbols-64.m
+++ b/test/CodeGenObjC/metadata-symbols-64.m
@@ -3,7 +3,7 @@
// RUN: grep '@"OBJC_CLASS_$_A" = global' %t
// RUN: grep '@"OBJC_CLASS_$_B" = external global' %t
-// RUN: grep '@"OBJC_IVAR_$_A._ivar" = global .* section "__DATA, __objc_const", align 8' %t
+// RUN: grep '@"OBJC_IVAR_$_A._ivar" = global .* section "__DATA, __objc_ivar", align 8' %t
// RUN: grep '@"OBJC_METACLASS_$_A" = global .* section "__DATA, __objc_data", align 8' %t
// RUN: grep '@"\\01L_OBJC_CLASSLIST_REFERENCES_$_[0-9]*" = internal global .* section "__DATA, __objc_classrefs, regular, no_dead_strip", align 8' %t
// RUN: grep '@"\\01L_OBJC_CLASSLIST_SUP_REFS_$_[0-9]*" = internal global .* section "__DATA, __objc_superrefs, regular, no_dead_strip", align 8' %t | count 2
diff --git a/test/CodeGenObjC/no-vararg-messaging.m b/test/CodeGenObjC/no-vararg-messaging.m
index f72820a..6747c0c 100644
--- a/test/CodeGenObjC/no-vararg-messaging.m
+++ b/test/CodeGenObjC/no-vararg-messaging.m
@@ -1,3 +1,4 @@
+// REQUIRES: x86-64-registered-target
// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fobjc-nonfragile-abi -S -o - %s | FileCheck %s
// rdar://9048030
diff --git a/test/CodeGenObjC/objc-read-weak-byref.m b/test/CodeGenObjC/objc-read-weak-byref.m
index fa7a6f9..c89fcd5 100644
--- a/test/CodeGenObjC/objc-read-weak-byref.m
+++ b/test/CodeGenObjC/objc-read-weak-byref.m
@@ -1,3 +1,4 @@
+// REQUIRES: x86-registered-target,x86-64-registered-target
// RUN: %clang_cc1 -fblocks -fobjc-gc -triple x86_64-apple-darwin -S %s -o %t-64.s
// RUN: FileCheck -check-prefix LP64 --input-file=%t-64.s %s
// RUN: %clang_cc1 -fblocks -fobjc-gc -triple i386-apple-darwin -S %s -o %t-32.s
diff --git a/test/CodeGenObjC/protocol-in-extended-class.m b/test/CodeGenObjC/protocol-in-extended-class.m
index d2955b1..daf4d4c 100644
--- a/test/CodeGenObjC/protocol-in-extended-class.m
+++ b/test/CodeGenObjC/protocol-in-extended-class.m
@@ -1,3 +1,4 @@
+// REQUIRES: x86-registered-target,x86-64-registered-target
// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fobjc-nonfragile-abi -S %s -o %t-64.s
// RUN: FileCheck -check-prefix LP64 --input-file=%t-64.s %s
// RUN: %clang_cc1 -triple i386-apple-darwin -S %s -o %t-32.s
diff --git a/test/CodeGenObjC/try.m b/test/CodeGenObjC/try.m
index ba79d62..56b8e64 100644
--- a/test/CodeGenObjC/try.m
+++ b/test/CodeGenObjC/try.m
@@ -1,3 +1,4 @@
+// REQUIRES: x86-registered-target,x86-64-registered-target
// RUN: %clang_cc1 %s -fobjc-exceptions -S -o - -triple=i686-apple-darwin9
// RUN: %clang_cc1 %s -fobjc-exceptions -S -o - -triple=x86_64-apple-darwin9
diff --git a/test/CodeGenObjC/unwind-fn.m b/test/CodeGenObjC/unwind-fn.m
deleted file mode 100644
index 5e4a7a5..0000000
--- a/test/CodeGenObjC/unwind-fn.m
+++ /dev/null
@@ -1,14 +0,0 @@
-// RUN: %clang_cc1 -fobjc-nonfragile-abi -emit-llvm -fexceptions -fobjc-exceptions -o - %s | FileCheck --check-prefix=DEFAULT_EH %s
-// RUN: %clang_cc1 -fsjlj-exceptions -fobjc-nonfragile-abi -fexceptions -fobjc-exceptions -emit-llvm -o - %s | FileCheck --check-prefix=SJLJ_EH %s
-
-// DEFAULT_EH: declare void @_Unwind_Resume_or_Rethrow(i8*)
-// SJLJ_EH: declare void @_Unwind_SjLj_Resume_or_Rethrow(i8*)
-
-void f1(), f2();
-void f0() {
- @try {
- f1();
- } @catch (...) {
- f2();
- }
-}
diff --git a/test/CodeGenObjCXX/block-in-template-inst.mm b/test/CodeGenObjCXX/block-in-template-inst.mm
new file mode 100644
index 0000000..72042fc
--- /dev/null
+++ b/test/CodeGenObjCXX/block-in-template-inst.mm
@@ -0,0 +1,71 @@
+// RUN: %clang_cc1 -emit-llvm-only -std=c++0x -fblocks -o - -triple x86_64-apple-darwin10 %s
+// rdar://9362021
+
+@class DYFuture;
+@interface NSCache
+- (void)setObject:(id)obj forKey:(id)key;
+@end
+
+template <typename T>
+class ResourceManager
+{
+public:
+ ~ResourceManager();
+ DYFuture* XXX();
+ NSCache* _spDeviceCache;
+};
+
+template <typename T>
+DYFuture* ResourceManager<T>::XXX()
+{
+ ^ {
+ [_spDeviceCache setObject:0 forKey:0];
+ }();
+
+ return 0;
+}
+
+struct AnalyzerBaseObjectTypes { };
+
+void FUNC()
+{
+ ResourceManager<AnalyzerBaseObjectTypes> *rm;
+ ^(void) { rm->XXX(); }();
+}
+
+namespace PR9982 {
+ template<typename T> struct Curry;
+
+ template<typename R, typename Arg0, typename Arg1, typename Arg2>
+ struct Curry<R (^)(Arg0, Arg1, Arg2)>
+ {
+ typedef R (^FType)(Arg0, Arg1, Arg2);
+
+ Curry(FType _f) : f(_f) {}
+ ~Curry() {;}
+
+ R (^(^operator()(Arg0 a))(Arg1))(Arg2)
+ {
+ auto block = ^(Arg1 b) {
+ auto inner_block = ^(Arg2 c) {
+ return f(a, b, c);
+ };
+ return inner_block;
+ };
+ return block;
+ }
+
+ private:
+ FType f;
+ };
+
+ auto add = ^(int a, int b, int c)
+ {
+ return a + b + c;
+ };
+
+ void curry() {
+ Curry<__decltype(add)> c = Curry<__decltype(add)>(add);
+ auto t = c(1)(10)(100);
+ }
+}
diff --git a/test/CodeGenObjCXX/blocks.mm b/test/CodeGenObjCXX/blocks.mm
index ffb916b..e220753 100644
--- a/test/CodeGenObjCXX/blocks.mm
+++ b/test/CodeGenObjCXX/blocks.mm
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -x objective-c++ -fblocks -triple x86_64-apple-darwin %s
+// RUN: %clang_cc1 -x objective-c++ -fblocks -triple x86_64-apple-darwin %s -verify -emit-llvm -o %t
// rdar://8979379
@interface A
@@ -28,3 +28,19 @@ void foo(id <NSObject>(^objectCreationBlock)(void)) {
return bar(objectCreationBlock);
}
+// Test4
+struct S {
+ S *(^a)() = ^{ // expected-warning {{C++0x}}
+ return this;
+ };
+};
+S s;
+
+// Test5
+struct X {
+ void f() {
+ ^ {
+ struct Nested { Nested *ptr = this; }; // expected-warning {{C++0x}}
+ } ();
+ };
+};
diff --git a/test/CodeGenObjCXX/encode.mm b/test/CodeGenObjCXX/encode.mm
index 5a49feb..dce3d70 100644
--- a/test/CodeGenObjCXX/encode.mm
+++ b/test/CodeGenObjCXX/encode.mm
@@ -62,3 +62,73 @@ typedef float HGVec4f __attribute__ ((vector_size(16)));
@implementation RedBalloonHGXFormWrapper
@end
+// rdar://9357400
+namespace rdar9357400 {
+ template<int Dim1 = -1, int Dim2 = -1> struct fixed {
+ template<int D> struct rebind { typedef fixed<D> other; };
+ };
+
+ template<typename Element, int Size>
+ class fixed_1D
+ {
+ public:
+ typedef Element value_type;
+ typedef value_type array_impl[Size];
+ protected:
+ array_impl m_data;
+ };
+
+ template<typename Element, typename Alloc>
+ class vector;
+
+ template<typename Element, int Size>
+ class vector< Element, fixed<Size> >
+ : public fixed_1D<Element,Size> { };
+
+ typedef vector< float, fixed<4> > vector4f;
+
+ // CHECK: @_ZN11rdar9357400L2ggE = internal constant [49 x i8] c"{vector<float, rdar9357400::fixed<4, -1> >=[4f]}\00"
+ const char gg[] = @encode(vector4f);
+}
+
+struct Base1 {
+ char x;
+};
+
+struct DBase : public Base1 {
+ double x;
+ virtual ~DBase();
+};
+
+struct Sub_with_virt : virtual DBase {
+ long x;
+};
+
+struct Sub2 : public Sub_with_virt, public Base1, virtual DBase {
+ float x;
+};
+
+// CHECK: @_ZL2g1 = internal constant [10 x i8] c"{Base1=c}\00"
+const char g1[] = @encode(Base1);
+
+// CHECK: @_ZL2g2 = internal constant [14 x i8] c"{DBase=^^?cd}\00"
+const char g2[] = @encode(DBase);
+
+// CHECK: @_ZL2g3 = internal constant [26 x i8] c"{Sub_with_virt=^^?q^^?cd}\00"
+const char g3[] = @encode(Sub_with_virt);
+
+// CHECK: @_ZL2g4 = internal constant [19 x i8] c"{Sub2=^^?qcf^^?cd}\00"
+const char g4[] = @encode(Sub2);
+
+// http://llvm.org/PR9927
+class allocator {
+};
+class basic_string {
+struct _Alloc_hider : allocator {
+char* _M_p;
+};
+_Alloc_hider _M_dataplus;
+};
+
+// CHECK: @_ZL2g5 = internal constant [32 x i8] c"{basic_string={_Alloc_hider=*}}\00"
+const char g5[] = @encode(basic_string);
diff --git a/test/CodeGenObjCXX/mangle.mm b/test/CodeGenObjCXX/mangle.mm
index 7a75a5b..2521c60 100644
--- a/test/CodeGenObjCXX/mangle.mm
+++ b/test/CodeGenObjCXX/mangle.mm
@@ -42,3 +42,15 @@
}
@end
+// rdar://9566314
+@interface NX
+- (void)Meth;
+@end
+
+@implementation NX
+- (void)Meth {
+ void uiIsVisible();
+// CHECK: call void @_Z11uiIsVisiblev
+ uiIsVisible();
+}
+@end
diff --git a/test/CodeGenObjCXX/property-object-conditional-exp.mm b/test/CodeGenObjCXX/property-object-conditional-exp.mm
index 826c351..a3c1027 100644
--- a/test/CodeGenObjCXX/property-object-conditional-exp.mm
+++ b/test/CodeGenObjCXX/property-object-conditional-exp.mm
@@ -23,7 +23,12 @@ extern "C" bool CGRectIsEmpty(CGRect);
CGRect virtualBounds;
// CHECK: [[SRC:%.*]] = call %struct.CGRect bitcast (i8* (i8*, i8*, ...)* @objc_msgSend
-// CHECK-NEXT:store %struct.CGRect [[SRC]], %struct.CGRect*
+// CHECK-NEXT:getelementptr %struct.CGRect* [[SRC:%.*]]
+// CHECK-NEXT:extractvalue
+// CHECK-NEXT:store
+// CHECK-NEXT:getelementptr %struct.CGRect* [[SRC:%.*]]
+// CHECK-NEXT:extractvalue
+// CHECK-NEXT:store
dataRect = CGRectIsEmpty(virtualBounds) ? self.bounds : virtualBounds;
dataRect = CGRectIsEmpty(virtualBounds) ? [self bounds] : virtualBounds;
dataRect = CGRectIsEmpty(virtualBounds) ? virtualBounds : self.bounds;
diff --git a/test/Driver/cc-log-diagnostics.c b/test/Driver/cc-log-diagnostics.c
index a70686a..6c1b8ed 100644
--- a/test/Driver/cc-log-diagnostics.c
+++ b/test/Driver/cc-log-diagnostics.c
@@ -1,7 +1,7 @@
+// RUN: rm -f %t.log
// RUN: env RC_DEBUG_OPTIONS=1 \
-// RUN: CC_LOG_DIAGNOSTICS=1 \
-// RUN: CC_LOG_DIAGNOSTICS_FILE=%t.log \
-// RUN: %clang -no-canonical-prefixes -ccc-host-triple x86_64-apple-darwin10 -fsyntax-only %s
+// RUN: CC_LOG_DIAGNOSTICS=1 CC_LOG_DIAGNOSTICS_FILE=%t.log \
+// RUN: %clang -Wfoobar -no-canonical-prefixes -ccc-host-triple x86_64-apple-darwin10 -fsyntax-only %s
// RUN: FileCheck %s < %t.log
int f0() {}
@@ -16,6 +16,12 @@ int f0() {}
// CHECK: <dict>
// CHECK: <key>level</key>
// CHECK: <string>warning</string>
+// CHECK: <key>message</key>
+// CHECK: <string>unknown warning option '-Wfoobar'</string>
+// CHECK: </dict>
+// CHECK: <dict>
+// CHECK: <key>level</key>
+// CHECK: <string>warning</string>
// CHECK: <key>filename</key>
// CHECK: <string>{{.*}}cc-log-diagnostics.c</string>
// CHECK: <key>line</key>
diff --git a/test/Driver/cfi.c b/test/Driver/cfi.c
new file mode 100644
index 0000000..b5c0c03
--- /dev/null
+++ b/test/Driver/cfi.c
@@ -0,0 +1,8 @@
+// RUN: %clang -ccc-host-triple i386-apple-darwin10 -static -### %s 2>&1 | \
+// RUN: FileCheck --check-prefix=CHECK-DARWIN %s
+
+// RUN: %clang -ccc-host-triple i386-pc-linux-gnu -static -### %s 2>&1 | \
+// RUN: FileCheck --check-prefix=CHECK-LINUX %s
+
+// CHECK-DARWIN: -fno-dwarf2-cfi-asm
+// CHECK-LINUX-NOT: -fno-dwarf2-cfi-asm
diff --git a/test/Driver/darwin-debug-flags.c b/test/Driver/darwin-debug-flags.c
index 3394e4e..326ca47 100644
--- a/test/Driver/darwin-debug-flags.c
+++ b/test/Driver/darwin-debug-flags.c
@@ -1,7 +1,7 @@
// RUN: env RC_DEBUG_OPTIONS=1 %clang -ccc-host-triple i386-apple-darwin9 -g -Os %s -emit-llvm -S -o - | FileCheck %s
// <rdar://problem/7256886>
-// CHECK: !1 = metadata !{
+// CHECK: !0 = metadata !{
// CHECK: -g -Os
// CHECK: -mmacosx-version-min=10.5.0
// CHECK: [ DW_TAG_compile_unit ]
diff --git a/test/Driver/darwin-ld.c b/test/Driver/darwin-ld.c
index 3f2b691..91d47ea 100644
--- a/test/Driver/darwin-ld.c
+++ b/test/Driver/darwin-ld.c
@@ -5,9 +5,9 @@
// Make sure we run dsymutil on source input files.
// RUN: %clang -ccc-host-triple i386-apple-darwin9 -### -g %s -o BAR 2> %t.log
-// RUN: grep '".*dsymutil" "BAR"' %t.log
+// RUN: grep '".*dsymutil" "-o" "BAR.dSYM" "BAR"' %t.log
// RUN: %clang -ccc-host-triple i386-apple-darwin9 -### -g -filelist FOO %s -o BAR 2> %t.log
-// RUN: grep '".*dsymutil" "BAR"' %t.log
+// RUN: grep '".*dsymutil" "-o" "BAR.dSYM" "BAR"' %t.log
// Splatter test case. This is gross, but it works for now. For the
// driver, just getting coverage of the tool code and checking the
@@ -19,7 +19,8 @@
// Note that at conception, this exactly matches gcc.
// RUN: %clang -ccc-host-triple i386-apple-darwin9 -### -A ARG0 -F ARG1 -L ARG2 -Mach -T ARG4 -X -Z -all_load -allowable_client ARG8 -bind_at_load -compatibility_version ARG11 -current_version ARG12 -d -dead_strip -dylib_file ARG14 -dylinker -dylinker_install_name ARG16 -dynamic -dynamiclib -e ARG19 -exported_symbols_list ARG20 -fexceptions -flat_namespace -fnested-functions -fopenmp -force_cpusubtype_ALL -fpie -fprofile-arcs -headerpad_max_install_names -image_base ARG29 -init ARG30 -install_name ARG31 -m ARG33 -mmacosx-version-min=10.3.2 -multi_module -multiply_defined ARG37 -multiply_defined_unused ARG38 -no_dead_strip_inits_and_terms -nodefaultlibs -nofixprebinding -nomultidefs -noprebind -noseglinkedit -nostartfiles -nostdlib -pagezero_size ARG54 -pg -prebind -prebind_all_twolevel_modules -preload -r -read_only_relocs ARG55 -s -sectalign ARG57_0 ARG57_1 ARG57_2 -sectcreate ARG58_0 ARG58_1 ARG58_2 -sectobjectsymbols ARG59_0 ARG59_1 -sectorder ARG60_0 ARG60_1 ARG60_2 -seg1addr ARG61 -seg_addr_table ARG62 -seg_addr_table_filename ARG63 -segaddr ARG64_0 ARG64_1 -segcreate ARG65_0 ARG65_1 ARG65_2 -seglinkedit -segprot ARG67_0 ARG67_1 ARG67_2 -segs_read_FOO -segs_read_only_addr ARG69 -segs_read_write_addr ARG70 -shared-libgcc -single_module -static -static-libgcc -sub_library ARG77 -sub_umbrella ARG78 -t -twolevel_namespace -twolevel_namespace_hints -u ARG82 -umbrella ARG83 -undefined ARG84 -unexported_symbols_list ARG85 -w -weak_reference_mismatches ARG87 -whatsloaded -whyload -y -filelist FOO -l FOO 2> %t.log
-// RUN: grep '".*ld.*" "-static" "-dylib" "-dylib_compatibility_version" "ARG11" "-dylib_current_version" "ARG12" "-arch" "i386" "-dylib_install_name" "ARG31" "-all_load" "-allowable_client" "ARG8" "-bind_at_load" "-dead_strip" "-no_dead_strip_inits_and_terms" "-dylib_file" "ARG14" "-dynamic" "-exported_symbols_list" "ARG20" "-flat_namespace" "-headerpad_max_install_names" "-image_base" "ARG29" "-init" "ARG30" "-macosx_version_min" "10.3.2" "-nomultidefs" "-multi_module" "-single_module" "-multiply_defined" "ARG37" "-multiply_defined_unused" "ARG38" "-pie" "-prebind" "-noprebind" "-nofixprebinding" "-prebind_all_twolevel_modules" "-read_only_relocs" "ARG55" "-sectcreate" "ARG58_0" "ARG58_1" "ARG58_2" "-sectorder" "ARG60_0" "ARG60_1" "ARG60_2" "-seg1addr" "ARG61" "-segprot" "ARG67_0" "ARG67_1" "ARG67_2" "-segaddr" "ARG64_0" "ARG64_1" "-segs_read_only_addr" "ARG69" "-segs_read_write_addr" "ARG70" "-seg_addr_table" "ARG62" "-seg_addr_table_filename" "ARG63" "-sub_library" "ARG77" "-sub_umbrella" "ARG78" "-twolevel_namespace" "-twolevel_namespace_hints" "-umbrella" "ARG83" "-undefined" "ARG84" "-unexported_symbols_list" "ARG85" "-weak_reference_mismatches" "ARG87" "-X" "-y" "-w" "-pagezero_size" "ARG54" "-segs_read_FOO" "-seglinkedit" "-noseglinkedit" "-sectalign" "ARG57_0" "ARG57_1" "ARG57_2" "-sectobjectsymbols" "ARG59_0" "ARG59_1" "-segcreate" "ARG65_0" "ARG65_1" "ARG65_2" "-whyload" "-whatsloaded" "-dylinker_install_name" "ARG16" "-dylinker" "-Mach" "-d" "-s" "-t" "-Z" "-u" "ARG82" "-undefined" "ARG84" "-A" "ARG0" "-e" "ARG19" "-m" "ARG33" "-r" "-o" "a.out" "-LARG2" "-lgomp".* "-filelist" "FOO" "-lFOO" "-lgcov" "-allow_stack_execute" "-T" "ARG4" "-FARG1"' %t.log
+// RUN: FileCheck -check-prefix=SPLATTER %s < %t.log
+// SPLATTER: {{".*ld.*" "-static" "-dylib" "-dylib_compatibility_version" "ARG11" "-dylib_current_version" "ARG12" "-arch" "i386" "-dylib_install_name" "ARG31" "-all_load" "-allowable_client" "ARG8" "-bind_at_load" "-dead_strip" "-no_dead_strip_inits_and_terms" "-dylib_file" "ARG14" "-dynamic" "-exported_symbols_list" "ARG20" "-flat_namespace" "-headerpad_max_install_names" "-image_base" "ARG29" "-init" "ARG30" "-macosx_version_min" "10.3.2" "-nomultidefs" "-multi_module" "-single_module" "-multiply_defined" "ARG37" "-multiply_defined_unused" "ARG38" "-pie" "-prebind" "-noprebind" "-nofixprebinding" "-prebind_all_twolevel_modules" "-read_only_relocs" "ARG55" "-sectcreate" "ARG58_0" "ARG58_1" "ARG58_2" "-sectorder" "ARG60_0" "ARG60_1" "ARG60_2" "-seg1addr" "ARG61" "-segprot" "ARG67_0" "ARG67_1" "ARG67_2" "-segaddr" "ARG64_0" "ARG64_1" "-segs_read_only_addr" "ARG69" "-segs_read_write_addr" "ARG70" "-seg_addr_table" "ARG62" "-seg_addr_table_filename" "ARG63" "-sub_library" "ARG77" "-sub_umbrella" "ARG78" "-twolevel_namespace" "-twolevel_namespace_hints" "-umbrella" "ARG83" "-undefined" "ARG84" "-unexported_symbols_list" "ARG85" "-weak_reference_mismatches" "ARG87" "-X" "-y" "-w" "-pagezero_size" "ARG54" "-segs_read_FOO" "-seglinkedit" "-noseglinkedit" "-sectalign" "ARG57_0" "ARG57_1" "ARG57_2" "-sectobjectsymbols" "ARG59_0" "ARG59_1" "-segcreate" "ARG65_0" "ARG65_1" "ARG65_2" "-whyload" "-whatsloaded" "-dylinker_install_name" "ARG16" "-dylinker" "-Mach" "-d" "-s" "-t" "-Z" "-u" "ARG82" "-undefined" "ARG84" "-A" "ARG0" "-e" "ARG19" "-m" "ARG33" "-r" "-o" "a.out" "-LARG2" "-lgomp".* "-filelist" "FOO" "-lFOO" "-allow_stack_execute" ".*/libprofile_rt.a" "-T" "ARG4" "-FARG1"}}
// Check linker changes that came with new linkedit format.
// RUN: touch %t.o
diff --git a/test/Driver/nostdlib.c b/test/Driver/nostdlib.c
new file mode 100644
index 0000000..c73212f
--- /dev/null
+++ b/test/Driver/nostdlib.c
@@ -0,0 +1,4 @@
+// RUN: %clang -ccc-host-triple i686-pc-linux-gnu -### -nostdlib %s 2> %t
+// RUN: FileCheck < %t %s
+//
+// CHECK-NOT: start-group
diff --git a/test/Driver/rewrite-objc.m b/test/Driver/rewrite-objc.m
index e3d2c0f..2fe2cce 100644
--- a/test/Driver/rewrite-objc.m
+++ b/test/Driver/rewrite-objc.m
@@ -3,7 +3,7 @@
// TEST0: clang{{.*}}" "-cc1"
// TEST0: "-rewrite-objc"
// FIXME: CHECK-NOT is broken somehow, it doesn't work here. Check adjacency instead.
-// TEST0: "-fmessage-length" "0" "-fobjc-exceptions" "-fdiagnostics-show-option"
+// TEST0: "-fmessage-length" "0" "-fobjc-infer-related-result-type" "-fobjc-exceptions" "-fdiagnostics-show-option"
// TEST0: rewrite-objc.m"
// RUN: not %clang -ccc-no-clang -ccc-host-triple unknown -rewrite-objc %s -o - -### 2>&1 | \
diff --git a/test/Driver/sysroot.c b/test/Driver/sysroot.c
new file mode 100644
index 0000000..34f3100
--- /dev/null
+++ b/test/Driver/sysroot.c
@@ -0,0 +1,18 @@
+// Check that --sysroot= also applies to header search paths.
+// RUN: %clang -ccc-host-triple i386-unk-unk --sysroot=/FOO -### -E %s 2> %t1
+// RUN: FileCheck --check-prefix=CHECK-SYSROOTEQ < %t1 %s
+// CHECK-SYSROOTEQ: "-cc1"{{.*}} "-isysroot" "/FOO"
+
+// Apple Darwin uses -isysroot as the syslib root, too.
+// RUN: touch %t2.o
+// RUN: %clang -ccc-host-triple i386-apple-darwin10 \
+// RUN: -isysroot /FOO -### %t2.o 2> %t2
+// RUN: FileCheck --check-prefix=CHECK-APPLE-ISYSROOT < %t2 %s
+// CHECK-APPLE-ISYSROOT: "-arch" "i386"{{.*}} "-syslibroot" "/FOO"
+
+// Check that honor --sysroot= over -isysroot, for Apple Darwin.
+// RUN: touch %t3.o
+// RUN: %clang -ccc-host-triple i386-apple-darwin10 \
+// RUN: -isysroot /FOO --sysroot=/BAR -### %t3.o 2> %t3
+// RUN: FileCheck --check-prefix=CHECK-APPLE-SYSROOT < %t3 %s
+// CHECK-APPLE-SYSROOT: "-arch" "i386"{{.*}} "-syslibroot" "/BAR"
diff --git a/test/FixIt/fixit-cxx0x.cpp b/test/FixIt/fixit-cxx0x.cpp
index 90bf9f5..77e9e58 100644
--- a/test/FixIt/fixit-cxx0x.cpp
+++ b/test/FixIt/fixit-cxx0x.cpp
@@ -1,6 +1,6 @@
// RUN: %clang_cc1 -verify -std=c++0x %s
// RUN: cp %s %t
-// RUN: %clang_cc1 -std=c++0x -fixit %t || true
+// RUN: %clang_cc1 -x c++ -std=c++0x -fixit %t || true
// RUN: %clang_cc1 -Wall -pedantic -x c++ -std=c++0x %t
/* This is a test of the various code modification hints that only
diff --git a/test/Frontend/diagnostic-name.c b/test/Frontend/diagnostic-name.c
index 7f43f65..ae6cb0d 100644
--- a/test/Frontend/diagnostic-name.c
+++ b/test/Frontend/diagnostic-name.c
@@ -1,5 +1,5 @@
-// RUN: %clang -Wunused-parameter -fdiagnostics-show-name %s 2>&1 | grep "\[warn_unused_parameter\]" | count 1
-// RUN: %clang -Wunused-parameter -fno-diagnostics-show-name %s 2>&1 | grep "\[warn_unused_parameter\]" | count 0
+// RUN: %clang -fsyntax-only -Wunused-parameter -fdiagnostics-show-name %s 2>&1 | grep "\[warn_unused_parameter\]" | count 1
+// RUN: %clang -fsyntax-only -Wunused-parameter -fno-diagnostics-show-name %s 2>&1 | grep "\[warn_unused_parameter\]" | count 0
int main(int argc, char *argv[]) {
return argc;
}
diff --git a/test/Frontend/ir-support-codegen.ll b/test/Frontend/ir-support-codegen.ll
index 046b3af..e5e5b62 100644
--- a/test/Frontend/ir-support-codegen.ll
+++ b/test/Frontend/ir-support-codegen.ll
@@ -1,3 +1,4 @@
+; REQUIRES: x86-64-registered-target
; RUN: %clang_cc1 -S -o - %s | FileCheck %s
target triple = "x86_64-apple-darwin10"
diff --git a/test/Frontend/undef.c b/test/Frontend/undef.c
new file mode 100644
index 0000000..f539cdc
--- /dev/null
+++ b/test/Frontend/undef.c
@@ -0,0 +1,4 @@
+// RUN: %clang -undef -x assembler-with-cpp -E %s
+#ifndef __ASSEMBLER__
+#error "Must be preprocessed as assembler."
+#endif
diff --git a/test/Index/Inputs/guarded.h b/test/Index/Inputs/guarded.h
new file mode 100644
index 0000000..0a1a6ac
--- /dev/null
+++ b/test/Index/Inputs/guarded.h
@@ -0,0 +1,6 @@
+#ifndef GUARDED_HEADER_H
+#define GUARDED_HEADER_H
+
+int y;
+
+#endif // GUARDED_HEADER_H
diff --git a/test/Index/Inputs/pragma-once.h b/test/Index/Inputs/pragma-once.h
new file mode 100644
index 0000000..503cb3f
--- /dev/null
+++ b/test/Index/Inputs/pragma-once.h
@@ -0,0 +1,3 @@
+#pragma once
+int i;
+
diff --git a/test/Index/annotate-context-sensitive.cpp b/test/Index/annotate-context-sensitive.cpp
index 307bced..151914c 100644
--- a/test/Index/annotate-context-sensitive.cpp
+++ b/test/Index/annotate-context-sensitive.cpp
@@ -28,12 +28,12 @@ struct Derived2 : Base2 {
// CHECK-OVERRIDE-FINAL: Identifier: "Base" [6:30 - 6:34] TypeRef=class Base:1:7
// CHECK-OVERRIDE-FINAL: Punctuation: "{" [6:35 - 6:36] ClassDecl=Derived:6:7 (Definition)
// CHECK-OVERRIDE-FINAL: Keyword: "virtual" [7:3 - 7:10] ClassDecl=Derived:6:7 (Definition)
-// CHECK-OVERRIDE-FINAL: Keyword: "void" [7:11 - 7:15] CXXMethod=f:7:16 [Overrides @3:16]
-// CHECK-OVERRIDE-FINAL: Identifier: "f" [7:16 - 7:17] CXXMethod=f:7:16 [Overrides @3:16]
-// CHECK-OVERRIDE-FINAL: Punctuation: "(" [7:17 - 7:18] CXXMethod=f:7:16 [Overrides @3:16]
-// CHECK-OVERRIDE-FINAL: Punctuation: ")" [7:18 - 7:19] CXXMethod=f:7:16 [Overrides @3:16]
-// CHECK-OVERRIDE-FINAL: Keyword: "override" [7:20 - 7:28] CXXMethod=f:7:16 [Overrides @3:16]
-// CHECK-OVERRIDE-FINAL: Keyword: "final" [7:29 - 7:34] CXXMethod=f:7:16 [Overrides @3:16]
+// CHECK-OVERRIDE-FINAL: Keyword: "void" [7:11 - 7:15] CXXMethod=f:7:16 (virtual) [Overrides @3:16]
+// CHECK-OVERRIDE-FINAL: Identifier: "f" [7:16 - 7:17] CXXMethod=f:7:16 (virtual) [Overrides @3:16]
+// CHECK-OVERRIDE-FINAL: Punctuation: "(" [7:17 - 7:18] CXXMethod=f:7:16 (virtual) [Overrides @3:16]
+// CHECK-OVERRIDE-FINAL: Punctuation: ")" [7:18 - 7:19] CXXMethod=f:7:16 (virtual) [Overrides @3:16]
+// CHECK-OVERRIDE-FINAL: Keyword: "override" [7:20 - 7:28] CXXMethod=f:7:16 (virtual) [Overrides @3:16]
+// CHECK-OVERRIDE-FINAL: Keyword: "final" [7:29 - 7:34] CXXMethod=f:7:16 (virtual) [Overrides @3:16]
// CHECK-OVERRIDE-FINAL: Punctuation: ";" [7:34 - 7:35] ClassDecl=Derived:6:7 (Definition)
// CHECK-OVERRIDE-FINAL: Keyword: "struct" [9:3 - 9:9] StructDecl=final:9:10 (Definition)
// CHECK-OVERRIDE-FINAL: Identifier: "final" [9:10 - 9:15] StructDecl=final:9:10 (Definition)
diff --git a/test/Index/annotate-tokens-pp.c b/test/Index/annotate-tokens-pp.c
index 3dd9ffe..01a615f 100644
--- a/test/Index/annotate-tokens-pp.c
+++ b/test/Index/annotate-tokens-pp.c
@@ -25,7 +25,10 @@ void test() {
fun_with_macro_bodies(x, { int z = x; ++z; });
}
-// RUN: c-index-test -test-annotate-tokens=%s:2:1:26:1 -I%S/Inputs %s | FileCheck %s
+#include "pragma-once.h"
+#include "guarded.h"
+
+// RUN: c-index-test -test-annotate-tokens=%s:2:1:30:1 -I%S/Inputs %s | FileCheck %s
// CHECK: Punctuation: "#" [2:1 - 2:2] preprocessing directive=
// CHECK: Identifier: "define" [2:2 - 2:8] preprocessing directive=
// CHECK: Identifier: "STILL_NOTHING" [2:9 - 2:22] macro definition=STILL_NOTHING
@@ -184,4 +187,5 @@ void test() {
// CHECK: Punctuation: ")" [25:47 - 25:48] UnexposedStmt=
// CHECK: Punctuation: ";" [25:48 - 25:49] UnexposedStmt=
// CHECK: Punctuation: "}" [26:1 - 26:2] UnexposedStmt=
-
+// CHECK: {{28:1.*inclusion directive=pragma-once.h.*multi-include guarded}}
+// CHECK: {{29:1.*inclusion directive=guarded.h.*multi-include guarded}}
diff --git a/test/Index/annotate-tokens.m b/test/Index/annotate-tokens.m
index f977e5c..1eb7794 100644
--- a/test/Index/annotate-tokens.m
+++ b/test/Index/annotate-tokens.m
@@ -500,10 +500,10 @@ static Rdar8595462_A * Rdar8595462_staticVar;
// CHECK: Punctuation: "*" [111:26 - 111:27] ObjCPropertyDecl=foo2:111:27
// CHECK: Identifier: "foo2" [111:27 - 111:31] ObjCPropertyDecl=foo2:111:27
-// CHECK: Punctuation: "@" [115:1 - 115:2] UnexposedDecl=foo:110:33 (Definition)
-// CHECK: Keyword: "synthesize" [115:2 - 115:12] UnexposedDecl=foo:110:33 (Definition)
-// CHECK: Identifier: "foo" [115:13 - 115:16] UnexposedDecl=foo:110:33 (Definition)
-// CHECK: Punctuation: "=" [115:17 - 115:18] UnexposedDecl=foo:110:33 (Definition)
+// CHECK: Punctuation: "@" [115:1 - 115:2] ObjCSynthesizeDecl=foo:110:33 (Definition)
+// CHECK: Keyword: "synthesize" [115:2 - 115:12] ObjCSynthesizeDecl=foo:110:33 (Definition)
+// CHECK: Identifier: "foo" [115:13 - 115:16] ObjCSynthesizeDecl=foo:110:33 (Definition)
+// CHECK: Punctuation: "=" [115:17 - 115:18] ObjCSynthesizeDecl=foo:110:33 (Definition)
// CHECK: Identifier: "_foo" [115:19 - 115:23] MemberRef=_foo:107:8
// CHECK: Punctuation: ";" [115:23 - 115:24] ObjCImplementationDecl=Rdar8595386:114:1 (Definition)
diff --git a/test/Index/complete-kvc.m b/test/Index/complete-kvc.m
index 43a874b..62d98a9 100644
--- a/test/Index/complete-kvc.m
+++ b/test/Index/complete-kvc.m
@@ -41,6 +41,17 @@ typedef signed char BOOL;
+ (NSSet *)keyPathsForValuesAffectingIntProperty { return 0; }
@end
+@interface MySubClass : MyClass
+@end
+
+@interface MySubClass ()
+@property int intProperty;
+@end
+
+@implementation MySubClass
+- (int)intProperty { return 0; }
+@end
+
// RUN: c-index-test -code-completion-at=%s:39:3 %s | FileCheck -check-prefix=CHECK-CC1 %s
// CHECK-CC1: ObjCInstanceMethodDecl:{LeftParen (}{Text void}{RightParen )}{TypedText addMutableArrayPropertyObject:}{LeftParen (}{Placeholder object-type}{Text *}{RightParen )}{Text object} (55)
// CHECK-CC1: ObjCInstanceMethodDecl:{LeftParen (}{Text void}{RightParen )}{TypedText addMutableSetProperty:}{LeftParen (}{Text NSSet *}{RightParen )}{Text objects} (40)
@@ -84,4 +95,11 @@ typedef signed char BOOL;
// CHECK-CC1: ObjCInstanceMethodDecl:{LeftParen (}{Text void}{RightParen )}{TypedText replaceObjectInMySetPropertyAtIndex:}{LeftParen (}{Placeholder NSUInteger}{RightParen )}{Text index}{HorizontalSpace }{TypedText withObject:}{LeftParen (}{Text id}{RightParen )}{Text object} (55)
// RUN: c-index-test -code-completion-at=%s:41:3 %s | FileCheck -check-prefix=CHECK-CC2 %s
-// CHECK-CC2: ObjCInstanceMethodDecl:{LeftParen (}{Text NSSet *}{RightParen )}{TypedText keyPathsForValuesAffectingMutableArrayProperty} (40)
+// CHECK-CC2: ObjCClassMethodDecl:{LeftParen (}{Text BOOL}{RightParen )}{TypedText automaticallyNotifiesObserversOfArrayProperty} (40)
+// CHECK-CC2: ObjCClassMethodDecl:{LeftParen (}{Text BOOL}{RightParen )}{TypedText automaticallyNotifiesObserversOfMutableArrayProperty} (40)
+// CHECK-CC2: ObjCClassMethodDecl:{LeftParen (}{Text NSSet *}{RightParen )}{TypedText keyPathsForValuesAffectingMutableArrayProperty} (40)
+
+// RUN: c-index-test -code-completion-at=%s:52:8 %s | FileCheck -check-prefix=CHECK-CC3 %s
+// CHECK-CC3: ObjCInstanceMethodDecl:{TypedText countOfIntProperty} (55)
+// CHECK-CC3-NEXT: ObjCInstanceMethodDecl:{TypedText intProperty} (40)
+// CHECK-CC3-NEXT: ObjCInstanceMethodDecl:{TypedText isIntProperty} (40)
diff --git a/test/Index/complete-member-access.m b/test/Index/complete-member-access.m
index ad2998c..bd68deb 100644
--- a/test/Index/complete-member-access.m
+++ b/test/Index/complete-member-access.m
@@ -22,9 +22,26 @@ void test_props(Int* ptr) {
ptr->IVar = 0;
}
+@interface Sub : Int
+@property int myProp;
+
+- (int)myProp;
+- (int)myOtherPropLikeThing;
+- (int)myOtherNonPropThing:(int)value;
+@end
+
+int test_more_props(Sub *s) {
+ return s.myOtherPropLikeThing;
+}
+
// RUN: c-index-test -code-completion-at=%s:21:7 %s | FileCheck -check-prefix=CHECK-CC1 %s
// 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} (35)
// CHECK-CC2: ObjCIvarDecl:{ResultType int}{TypedText SuperIVar} (37)
+// RUN: c-index-test -code-completion-at=%s:34:12 %s | FileCheck -check-prefix=CHECK-CC3 %s
+// CHECK-CC3: ObjCInstanceMethodDecl:{ResultType int}{TypedText myOtherPropLikeThing} (37)
+// CHECK-CC3: ObjCPropertyDecl:{ResultType int}{TypedText myProp} (35)
+// CHECK-CC3: ObjCPropertyDecl:{ResultType int}{TypedText prop1} (35)
+// CHECK-CC3: ObjCPropertyDecl:{ResultType float}{TypedText ProtoProp} (35)
diff --git a/test/Index/complete-property-flags.m b/test/Index/complete-property-flags.m
index cd3696f..af9e214 100644
--- a/test/Index/complete-property-flags.m
+++ b/test/Index/complete-property-flags.m
@@ -8,6 +8,7 @@
@property(retain, nonatomic) id xx;
// RUN: c-index-test -code-completion-at=%s:7:11 %s | FileCheck -check-prefix=CHECK-CC1 %s
// CHECK-CC1: {TypedText assign}
+// CHECK-CC1-NEXT: {TypedText atomic}
// CHECK-CC1-NEXT: {TypedText copy}
// CHECK-CC1-NEXT: {TypedText getter}{Text = }{Placeholder method}
// CHECK-CC1-NEXT: {TypedText nonatomic}
diff --git a/test/Index/nested-macro-instantiations.cpp b/test/Index/nested-macro-instantiations.cpp
new file mode 100644
index 0000000..d0c9bbb1
--- /dev/null
+++ b/test/Index/nested-macro-instantiations.cpp
@@ -0,0 +1,20 @@
+#define FOO(x) x
+#define BAR(x) FOO(x)
+#define WIBBLE(x) BAR(x)
+
+WIBBLE(int x);
+
+// RUN: env CINDEXTEST_NESTED_MACROS=1 c-index-test -test-load-source all %s | FileCheck -check-prefix CHECK-WITH-NESTED %s
+// RUN: env CINDEXTEST_EDITING=1 CINDEXTEST_NESTED_MACROS=1 c-index-test -test-load-source all %s | FileCheck -check-prefix CHECK-WITH-NESTED %s
+// RUN: env CINDEXTEST_EDITING=1 CINDEXTEST_NESTED_MACROS=1 c-index-test -test-load-source-reparse 5 all %s | FileCheck -check-prefix CHECK-WITH-NESTED %s
+// CHECK-WITH-NESTED: nested-macro-instantiations.cpp:5:1: macro instantiation=WIBBLE:3:9 Extent=[5:1 - 5:7]
+// CHECK-WITH-NESTED: nested-macro-instantiations.cpp:3:19: macro instantiation=BAR:2:9 Extent=[3:19 - 5:14]
+// CHECK-WITH-NESTED: nested-macro-instantiations.cpp:2:16: macro instantiation=FOO:1:9 Extent=[2:16 - 5:14]
+// CHECK-WITH-NESTED: nested-macro-instantiations.cpp:5:1: VarDecl=x:5:1 (Definition) Extent=[5:1 - 5:14]
+
+// RUN: c-index-test -test-load-source all %s | FileCheck -check-prefix CHECK-WITHOUT-NESTED %s
+// RUN: env CINDEXTEST_EDITING=1 c-index-test -test-load-source all %s | FileCheck -check-prefix CHECK-WITHOUT-NESTED %s
+// RUN: env CINDEXTEST_EDITING=1 c-index-test -test-load-source-reparse 5 all %s | FileCheck -check-prefix CHECK-WITHOUT-NESTED %s
+// CHECK-WITHOUT-NESTED: nested-macro-instantiations.cpp:5:1: macro instantiation=WIBBLE:3:9 Extent=[5:1 - 5:7]
+// CHECK-WITHOUT-NESTED-NOT: nested-macro-instantiations.cpp:3:19: macro instantiation=BAR:2:9 Extent=[3:19 - 5:14]
+// CHECK-WITHOUT-NESTED: nested-macro-instantiations.cpp:5:1: VarDecl=x:5:1 (Definition) Extent=[5:1 - 5:14]
diff --git a/test/Index/overrides.cpp b/test/Index/overrides.cpp
index ed24cc5..698b256 100644
--- a/test/Index/overrides.cpp
+++ b/test/Index/overrides.cpp
@@ -16,5 +16,5 @@ struct D : C {
};
// RUN: c-index-test -test-load-source local %s | FileCheck %s
-// CHECK: overrides.cpp:11:16: CXXMethod=g:11:16 [Overrides @7:16] Extent=[11:3 - 11:19]
-// CHECK: overrides.cpp:15:16: CXXMethod=f:15:16 [Overrides @2:16, @6:16] Extent=[15:3 - 15:22]
+// CHECK: overrides.cpp:11:16: CXXMethod=g:11:16 (virtual) [Overrides @7:16] Extent=[11:3 - 11:19]
+// CHECK: overrides.cpp:15:16: CXXMethod=f:15:16 (virtual) [Overrides @2:16, @6:16] Extent=[15:3 - 15:22]
diff --git a/test/Index/properties-class-extensions.m b/test/Index/properties-class-extensions.m
index ecedc60..de61242 100644
--- a/test/Index/properties-class-extensions.m
+++ b/test/Index/properties-class-extensions.m
@@ -95,5 +95,5 @@
// CHECK: properties-class-extensions.m:38:34: ObjCInstanceMethodDecl=qux:38:34 Extent=[38:34 - 38:37]
// CHECK: properties-class-extensions.m:38:34: ObjCInstanceMethodDecl=setQux::38:34 Extent=[38:34 - 38:37]
// CHECK: properties-class-extensions.m:38:34: ParmDecl=qux:38:34 (Definition) Extent=[38:34 - 38:37]
-// CHECK: properties-class-extensions.m:42:10: UnexposedDecl=qux:38:34 (Definition) Extent=[42:1 - 42:13]
+// CHECK: properties-class-extensions.m:42:10: ObjCDynamicDecl=qux:38:34 (Definition) Extent=[42:1 - 42:13]
diff --git a/test/Index/recursive-cxx-member-calls.cpp b/test/Index/recursive-cxx-member-calls.cpp
index 6170fdc..4c24083 100644
--- a/test/Index/recursive-cxx-member-calls.cpp
+++ b/test/Index/recursive-cxx-member-calls.cpp
@@ -399,13 +399,13 @@ AttributeList::Kind AttributeList::getKind(const IdentifierInfo * Name) {
// CHECK-tokens: Punctuation: ";" [32:6 - 32:7] ClassDecl=AttributeList:12:9 (Definition)
// CHECK-tokens: Keyword: "static" [33:5 - 33:11] ClassDecl=AttributeList:12:9 (Definition)
// CHECK-tokens: Identifier: "Kind" [33:12 - 33:16] TypeRef=enum clang::AttributeList::Kind:13:10
-// CHECK-tokens: Identifier: "getKind" [33:17 - 33:24] CXXMethod=getKind:33:17
-// CHECK-tokens: Punctuation: "(" [33:24 - 33:25] CXXMethod=getKind:33:17
-// CHECK-tokens: Keyword: "const" [33:25 - 33:30] CXXMethod=getKind:33:17
+// CHECK-tokens: Identifier: "getKind" [33:17 - 33:24] CXXMethod=getKind:33:17 (static)
+// CHECK-tokens: Punctuation: "(" [33:24 - 33:25] CXXMethod=getKind:33:17 (static)
+// CHECK-tokens: Keyword: "const" [33:25 - 33:30] CXXMethod=getKind:33:17 (static)
// CHECK-tokens: Identifier: "IdentifierInfo" [33:31 - 33:45] TypeRef=class clang::IdentifierInfo:66:7
// CHECK-tokens: Punctuation: "*" [33:46 - 33:47] ParmDecl=Name:33:48 (Definition)
// CHECK-tokens: Identifier: "Name" [33:48 - 33:52] ParmDecl=Name:33:48 (Definition)
-// CHECK-tokens: Punctuation: ")" [33:52 - 33:53] CXXMethod=getKind:33:17
+// CHECK-tokens: Punctuation: ")" [33:52 - 33:53] CXXMethod=getKind:33:17 (static)
// CHECK-tokens: Punctuation: ";" [33:53 - 33:54] ClassDecl=AttributeList:12:9 (Definition)
// CHECK-tokens: Punctuation: "}" [34:3 - 34:4] ClassDecl=AttributeList:12:9 (Definition)
// CHECK-tokens: Punctuation: ";" [34:4 - 34:5] Namespace=clang:10:17 (Definition)
@@ -456,14 +456,14 @@ AttributeList::Kind AttributeList::getKind(const IdentifierInfo * Name) {
// CHECK-tokens: Punctuation: ";" [44:16 - 44:17] ClassDecl=StringRef:38:7 (Definition)
// CHECK-tokens: Keyword: "static" [45:3 - 45:9] ClassDecl=StringRef:38:7 (Definition)
// CHECK-tokens: Identifier: "size_t" [45:10 - 45:16] TypeRef=size_t:2:25
-// CHECK-tokens: Identifier: "min" [45:17 - 45:20] CXXMethod=min:45:17 (Definition)
-// CHECK-tokens: Punctuation: "(" [45:20 - 45:21] CXXMethod=min:45:17 (Definition)
+// CHECK-tokens: Identifier: "min" [45:17 - 45:20] CXXMethod=min:45:17 (Definition) (static)
+// CHECK-tokens: Punctuation: "(" [45:20 - 45:21] CXXMethod=min:45:17 (Definition) (static)
// CHECK-tokens: Identifier: "size_t" [45:21 - 45:27] TypeRef=size_t:2:25
// CHECK-tokens: Identifier: "a" [45:28 - 45:29] ParmDecl=a:45:28 (Definition)
-// CHECK-tokens: Punctuation: "," [45:29 - 45:30] CXXMethod=min:45:17 (Definition)
+// CHECK-tokens: Punctuation: "," [45:29 - 45:30] CXXMethod=min:45:17 (Definition) (static)
// CHECK-tokens: Identifier: "size_t" [45:31 - 45:37] TypeRef=size_t:2:25
// CHECK-tokens: Identifier: "b" [45:38 - 45:39] ParmDecl=b:45:38 (Definition)
-// CHECK-tokens: Punctuation: ")" [45:39 - 45:40] CXXMethod=min:45:17 (Definition)
+// CHECK-tokens: Punctuation: ")" [45:39 - 45:40] CXXMethod=min:45:17 (Definition) (static)
// CHECK-tokens: Punctuation: "{" [45:41 - 45:42] UnexposedStmt=
// CHECK-tokens: Keyword: "return" [45:43 - 45:49] UnexposedStmt=
// CHECK-tokens: Identifier: "a" [45:50 - 45:51] DeclRefExpr=a:45:28
@@ -893,17 +893,17 @@ AttributeList::Kind AttributeList::getKind(const IdentifierInfo * Name) {
// CHECK-tokens: Identifier: "clang" [98:17 - 98:22] NamespaceRef=clang:10:17
// CHECK-tokens: Punctuation: ";" [98:22 - 98:23]
// CHECK-tokens: Identifier: "AttributeList" [100:1 - 100:14] TypeRef=class clang::AttributeList:12:9
-// CHECK-tokens: Punctuation: "::" [100:14 - 100:16] CXXMethod=getKind:100:36 (Definition)
+// CHECK-tokens: Punctuation: "::" [100:14 - 100:16] CXXMethod=getKind:100:36 (Definition) (static)
// CHECK-tokens: Identifier: "Kind" [100:16 - 100:20] TypeRef=enum clang::AttributeList::Kind:13:10
// CHECK-tokens: Identifier: "AttributeList" [100:21 - 100:34] TypeRef=class clang::AttributeList:12:9
-// CHECK-tokens: Punctuation: "::" [100:34 - 100:36] CXXMethod=getKind:100:36 (Definition)
-// CHECK-tokens: Identifier: "getKind" [100:36 - 100:43] CXXMethod=getKind:100:36 (Definition)
-// CHECK-tokens: Punctuation: "(" [100:43 - 100:44] CXXMethod=getKind:100:36 (Definition)
-// CHECK-tokens: Keyword: "const" [100:44 - 100:49] CXXMethod=getKind:100:36 (Definition)
+// CHECK-tokens: Punctuation: "::" [100:34 - 100:36] CXXMethod=getKind:100:36 (Definition) (static)
+// CHECK-tokens: Identifier: "getKind" [100:36 - 100:43] CXXMethod=getKind:100:36 (Definition) (static)
+// CHECK-tokens: Punctuation: "(" [100:43 - 100:44] CXXMethod=getKind:100:36 (Definition) (static)
+// CHECK-tokens: Keyword: "const" [100:44 - 100:49] CXXMethod=getKind:100:36 (Definition) (static)
// CHECK-tokens: Identifier: "IdentifierInfo" [100:50 - 100:64] TypeRef=class clang::IdentifierInfo:66:7
// CHECK-tokens: Punctuation: "*" [100:65 - 100:66] ParmDecl=Name:100:67 (Definition)
// CHECK-tokens: Identifier: "Name" [100:67 - 100:71] ParmDecl=Name:100:67 (Definition)
-// CHECK-tokens: Punctuation: ")" [100:71 - 100:72] CXXMethod=getKind:100:36 (Definition)
+// CHECK-tokens: Punctuation: ")" [100:71 - 100:72] CXXMethod=getKind:100:36 (Definition) (static)
// CHECK-tokens: Punctuation: "{" [100:73 - 100:74] UnexposedStmt=
// CHECK-tokens: Identifier: "llvm" [101:3 - 101:7] NamespaceRef=llvm:82:11
// CHECK-tokens: Punctuation: "::" [101:7 - 101:9] VarDecl=AttrName:101:19 (Definition)
@@ -1616,7 +1616,7 @@ AttributeList::Kind AttributeList::getKind(const IdentifierInfo * Name) {
// CHECK: 30:40: EnumConstantDecl=AT_init_priority:30:40 (Definition) Extent=[30:40 - 30:56]
// CHECK: 31:7: EnumConstantDecl=IgnoredAttribute:31:7 (Definition) Extent=[31:7 - 31:23]
// CHECK: 31:25: EnumConstantDecl=UnknownAttribute:31:25 (Definition) Extent=[31:25 - 31:41]
-// CHECK: 33:17: CXXMethod=getKind:33:17 Extent=[33:5 - 33:53]
+// CHECK: 33:17: CXXMethod=getKind:33:17 (static) Extent=[33:5 - 33:53]
// CHECK: 33:12: TypeRef=enum clang::AttributeList::Kind:13:10 Extent=[33:12 - 33:16]
// CHECK: 33:48: ParmDecl=Name:33:48 (Definition) Extent=[33:25 - 33:52]
// CHECK: 33:31: TypeRef=class clang::IdentifierInfo:66:7 Extent=[33:31 - 33:45]
@@ -1638,7 +1638,7 @@ AttributeList::Kind AttributeList::getKind(const IdentifierInfo * Name) {
// CHECK: 43:15: FieldDecl=Data:43:15 (Definition) Extent=[43:3 - 43:19]
// CHECK: 44:10: FieldDecl=Length:44:10 (Definition) Extent=[44:3 - 44:16]
// CHECK: 44:3: TypeRef=size_t:2:25 Extent=[44:3 - 44:9]
-// CHECK: 45:17: CXXMethod=min:45:17 (Definition) Extent=[45:3 - 45:66]
+// CHECK: 45:17: CXXMethod=min:45:17 (Definition) (static) Extent=[45:3 - 45:66]
// CHECK: 45:10: TypeRef=size_t:2:25 Extent=[45:10 - 45:16]
// CHECK: 45:28: ParmDecl=a:45:28 (Definition) Extent=[45:21 - 45:29]
// CHECK: 45:21: TypeRef=size_t:2:25 Extent=[45:21 - 45:27]
@@ -1865,7 +1865,7 @@ AttributeList::Kind AttributeList::getKind(const IdentifierInfo * Name) {
// CHECK: 93:12: DeclRefExpr=Value:92:23 Extent=[93:12 - 93:17]
// CHECK: 98:17: UsingDirective=:98:17 Extent=[98:1 - 98:22]
// CHECK: 98:17: NamespaceRef=clang:10:17 Extent=[98:17 - 98:22]
-// CHECK: 100:36: CXXMethod=getKind:100:36 (Definition) Extent=[100:1 - 186:2]
+// CHECK: 100:36: CXXMethod=getKind:100:36 (Definition) (static) Extent=[100:1 - 186:2]
// CHECK: 100:21: TypeRef=class clang::AttributeList:12:9 Extent=[100:21 - 100:34]
// CHECK: 100:67: ParmDecl=Name:100:67 (Definition) Extent=[100:44 - 100:71]
// CHECK: 100:50: TypeRef=class clang::IdentifierInfo:66:7 Extent=[100:50 - 100:64]
diff --git a/test/Index/usrs.cpp b/test/Index/usrs.cpp
index a43b689..023818c 100644
--- a/test/Index/usrs.cpp
+++ b/test/Index/usrs.cpp
@@ -65,6 +65,20 @@ using foo::ClsB;
namespace foo_alias3 = foo;
+namespace {
+class RDar9371763_Foo {
+public:
+ void bar();
+};
+}
+
+void RDar9371763_Foo::bar() {}
+
+void rdar9371763() {
+ RDar9371763_Foo foo;
+ foo.bar();
+}
+
// RUN: c-index-test -test-load-source-usrs all %s | FileCheck %s
// CHECK: usrs.cpp c:@N@foo Extent=[1:1 - 4:2]
// CHECK: usrs.cpp c:@N@foo@x Extent=[2:3 - 2:8]
@@ -122,3 +136,11 @@ namespace foo_alias3 = foo;
// CHECK: usrs.cpp c:@NA@foo_alias2
// CHECK-NOT: ClsB
// CHECK: usrs.cpp c:@NA@foo_alias3
+// CHECK: usrs.cpp c:@aN Extent=[68:1 - 73:2]
+// CHECK: usrs.cpp c:@aN@C@RDar9371763_Foo Extent=[69:1 - 72:2]
+// CHECK: usrs.cpp c: Extent=[70:1 - 70:8]
+// CHECK: usrs.cpp c:usrs.cpp@1131@aN@C@RDar9371763_Foo@F@bar# Extent=[71:3 - 71:13]
+// CHECK: usrs.cpp c:usrs.cpp@1131@aN@C@RDar9371763_Foo@F@bar# Extent=[75:1 - 75:31]
+// CHECK: usrs.cpp c:@F@rdar9371763# Extent=[77:1 - 80:2]
+// CHECK: usrs.cpp c:usrs.cpp@1204@F@rdar9371763#@foo Extent=[78:3 - 78:22]
+
diff --git a/test/Index/usrs.m b/test/Index/usrs.m
index 4b79fdc..2830647 100644
--- a/test/Index/usrs.m
+++ b/test/Index/usrs.m
@@ -195,7 +195,7 @@ int test_multi_declaration(void) {
// CHECK-source: usrs.m:42:10: UnexposedExpr= Extent=[42:10 - 42:11]
// CHECK-source: usrs.m:42:10: UnexposedExpr= Extent=[42:10 - 42:11]
// CHECK-source: usrs.m:44:13: ObjCIvarDecl=d1:44:13 (Definition) Extent=[44:13 - 44:15]
-// CHECK-source: usrs.m:44:13: UnexposedDecl=d1:31:15 (Definition) Extent=[44:1 - 44:15]
+// CHECK-source: usrs.m:44:13: ObjCSynthesizeDecl=d1:31:15 (Definition) Extent=[44:1 - 44:15]
// CHECK-source: usrs.m:47:5: VarDecl=z:47:5 Extent=[47:1 - 47:6]
// CHECK-source: usrs.m:49:12: FunctionDecl=local_func:49:12 (Definition) Extent=[49:1 - 49:43]
// CHECK-source: usrs.m:49:27: ParmDecl=x:49:27 (Definition) Extent=[49:23 - 49:28]
diff --git a/test/Lexer/block_cmt_end.c b/test/Lexer/block_cmt_end.c
index b03fb23..f54b6a4 100644
--- a/test/Lexer/block_cmt_end.c
+++ b/test/Lexer/block_cmt_end.c
@@ -1,7 +1,7 @@
/*
RUN: %clang_cc1 -E -trigraphs %s | grep bar
RUN: %clang_cc1 -E -trigraphs %s | grep foo
- RUN: %clang_cc1 -E -trigraphs %s | not grep abc
+ RUN: %clang_cc1 -E -trigraphs %s | not grep qux
RUN: %clang_cc1 -E -trigraphs %s | not grep xyz
RUN: %clang_cc1 -fsyntax-only -trigraphs -verify %s
*/
@@ -9,7 +9,7 @@
// This is a simple comment, /*/ does not end a comment, the trailing */ does.
int i = /*/ */ 1;
-/* abc
+/* qux
next comment ends with normal escaped newline:
*/
@@ -32,7 +32,3 @@ foo
// rdar://6060752 - We should not get warnings about trigraphs in comments:
// '????'
/* ???? */
-
-
-
-
diff --git a/test/Lexer/has_extension.c b/test/Lexer/has_extension.c
new file mode 100644
index 0000000..bc75a4a
--- /dev/null
+++ b/test/Lexer/has_extension.c
@@ -0,0 +1,30 @@
+// RUN: %clang_cc1 -E %s -o - | FileCheck --check-prefix=CHECK-PED-NONE %s
+// RUN: %clang_cc1 -pedantic-errors -E %s -o - | FileCheck --check-prefix=CHECK-PED-ERR %s
+
+// CHECK-PED-NONE: no_dummy_extension
+#if !__has_extension(dummy_extension)
+int no_dummy_extension();
+#endif
+
+// Arbitrary feature to test that has_extension is a superset of has_feature
+// CHECK-PED-NONE: attribute_overloadable
+#if __has_extension(attribute_overloadable)
+int attribute_overloadable();
+#endif
+
+// CHECK-PED-NONE: has_c_static_assert
+// CHECK-PED-ERR: no_c_static_assert
+#if __has_extension(c_static_assert)
+int has_c_static_assert();
+#else
+int no_c_static_assert();
+#endif
+
+// CHECK-PED-NONE: has_c_generic_selections
+// CHECK-PED-ERR: no_c_generic_selections
+#if __has_extension(c_generic_selections)
+int has_c_generic_selections();
+#else
+int no_c_generic_selections();
+#endif
+
diff --git a/test/Lexer/has_extension_cxx.cpp b/test/Lexer/has_extension_cxx.cpp
new file mode 100644
index 0000000..77efa35
--- /dev/null
+++ b/test/Lexer/has_extension_cxx.cpp
@@ -0,0 +1,36 @@
+// RUN: %clang_cc1 -E %s -o - | FileCheck %s
+
+// CHECK: c_static_assert
+#if __has_extension(c_static_assert)
+int c_static_assert();
+#endif
+
+// CHECK: c_generic_selections
+#if __has_extension(c_generic_selections)
+int c_generic_selections();
+#endif
+
+// CHECK: has_deleted_functions
+#if __has_extension(cxx_deleted_functions)
+int has_deleted_functions();
+#endif
+
+// CHECK: has_inline_namespaces
+#if __has_extension(cxx_inline_namespaces)
+int has_inline_namespaces();
+#endif
+
+// CHECK: has_override_control
+#if __has_extension(cxx_override_control)
+int has_override_control();
+#endif
+
+// CHECK: has_reference_qualified_functions
+#if __has_extension(cxx_reference_qualified_functions)
+int has_reference_qualified_functions();
+#endif
+
+// CHECK: has_rvalue_references
+#if __has_extension(cxx_rvalue_references)
+int has_rvalue_references();
+#endif
diff --git a/test/Lexer/has_feature_c1x.c b/test/Lexer/has_feature_c1x.c
new file mode 100644
index 0000000..6c0fb21
--- /dev/null
+++ b/test/Lexer/has_feature_c1x.c
@@ -0,0 +1,20 @@
+// RUN: %clang_cc1 -E -std=c1x %s -o - | FileCheck --check-prefix=CHECK-1X %s
+// RUN: %clang_cc1 -E %s -o - | FileCheck --check-prefix=CHECK-NO-1X %s
+
+#if __has_feature(c_static_assert)
+int has_static_assert();
+#else
+int no_static_assert();
+#endif
+
+// CHECK-1X: has_static_assert
+// CHECK-NO-1X: no_static_assert
+
+#if __has_feature(c_generic_selections)
+int has_generic_selections();
+#else
+int no_generic_selections();
+#endif
+
+// CHECK-1X: has_generic_selections
+// CHECK-NO-1X: no_generic_selections
diff --git a/test/Lexer/has_feature_cxx0x.cpp b/test/Lexer/has_feature_cxx0x.cpp
index 57949e3..ca5f868 100644
--- a/test/Lexer/has_feature_cxx0x.cpp
+++ b/test/Lexer/has_feature_cxx0x.cpp
@@ -17,7 +17,7 @@ int has_nullptr();
int no_nullptr();
#endif
-// CHECK-0X: no_nullptr
+// CHECK-0X: has_nullptr
// CHECK-NO-0X: no_nullptr
@@ -155,3 +155,12 @@ int no_override_control();
// CHECK-0X: has_override_control
// CHECK-NO-0X: no_override_control
+
+#if __has_feature(cxx_alias_templates)
+int has_alias_templates();
+#else
+int no_alias_templates();
+#endif
+
+// CHECK-0X: has_alias_templates
+// CHECK-NO-0X: no_alias_templates
diff --git a/test/Lexer/has_feature_type_traits.cpp b/test/Lexer/has_feature_type_traits.cpp
index 3cfc602..5da845f 100644
--- a/test/Lexer/has_feature_type_traits.cpp
+++ b/test/Lexer/has_feature_type_traits.cpp
@@ -89,3 +89,13 @@ int is_union();
int is_literal();
#endif
// CHECK: int is_literal();
+
+#if __has_feature(is_standard_layout)
+int is_standard_layout();
+#endif
+// CHECK: int is_standard_layout();
+
+#if __has_feature(is_trivially_copyable)
+int is_trivially_copyable();
+#endif
+// CHECK: int is_trivially_copyable();
diff --git a/test/Misc/Inputs/include.h b/test/Misc/Inputs/include.h
index d325775..72835e9 100644
--- a/test/Misc/Inputs/include.h
+++ b/test/Misc/Inputs/include.h
@@ -1 +1,3 @@
+#define EQUALS(a,b) a == b
+
int foo(int x) { return x; }
diff --git a/test/Misc/diag-format.c b/test/Misc/diag-format.c
new file mode 100644
index 0000000..39760b1
--- /dev/null
+++ b/test/Misc/diag-format.c
@@ -0,0 +1,34 @@
+// RUN: %clang -fsyntax-only %s 2>&1 | FileCheck %s -check-prefix=DEFAULT
+// RUN: %clang -fsyntax-only -fdiagnostics-format=clang %s 2>&1 | FileCheck %s -check-prefix=DEFAULT
+// RUN: %clang -fsyntax-only -fdiagnostics-format=clang -ccc-host-triple x86_64-pc-win32 %s 2>&1 | FileCheck %s -check-prefix=DEFAULT
+//
+// RUN: %clang -fsyntax-only -fdiagnostics-format=msvc %s 2>&1 | FileCheck %s -check-prefix=MSVC
+// RUN: %clang -fsyntax-only -fdiagnostics-format=msvc -ccc-host-triple x86_64-pc-win32 %s 2>&1 | FileCheck %s -check-prefix=MSVC
+// RUN: %clang -fsyntax-only -fdiagnostics-format=msvc -ccc-host-triple x86_64-pc-win32 -fshow-column %s 2>&1 | FileCheck %s -check-prefix=MSVC
+//
+// RUN: %clang -fsyntax-only -fdiagnostics-format=vi %s 2>&1 | FileCheck %s -check-prefix=VI
+//
+// RUN: %clang -fsyntax-only -fdiagnostics-format=msvc -fno-show-column %s 2>&1 | FileCheck %s -check-prefix=MSVC_ORIG
+//
+// RUN: %clang -fsyntax-only -fno-show-column %s 2>&1 | FileCheck %s -check-prefix=NO_COLUMN
+//
+
+
+
+
+
+
+
+
+
+
+
+
+#ifdef foo
+#endif bad // extension!
+// DEFAULT: {{.*}}:28:8: warning: extra tokens at end of #endif directive [-Wextra-tokens]
+// MSVC: {{.*}}(28,7) : warning: extra tokens at end of #endif directive [-Wextra-tokens]
+// VI: {{.*}} +28:8: warning: extra tokens at end of #endif directive [-Wextra-tokens]
+// MSVC_ORIG: {{.*}}(28) : warning: extra tokens at end of #endif directive [-Wextra-tokens]
+// NO_COLUMN: {{.*}}:28: warning: extra tokens at end of #endif directive [-Wextra-tokens]
+int x;
diff --git a/test/Misc/include-stack-for-note-flag.cpp b/test/Misc/include-stack-for-note-flag.cpp
index f8d0080..328999d 100644
--- a/test/Misc/include-stack-for-note-flag.cpp
+++ b/test/Misc/include-stack-for-note-flag.cpp
@@ -9,10 +9,20 @@ int test() {
return foo(1, 1);
}
+bool macro(int x, int y) {
+ return EQUALS(&x, y);
+}
+
// STACK: error: no matching function for call to 'foo'
// STACK: In file included from
// STACK: note: candidate function not viable
+// STACK: error: comparison between pointer and integer
+// STACK: In file included from
+// STACK: note: instantiated from:
// STACKLESS: error: no matching function for call to 'foo'
// STACKLESS-NOT: In file included from
// STACKLESS: note: candidate function not viable
+// STACKLESS: error: comparison between pointer and integer
+// STACKLESS-NOT: In file included from
+// STACKLESS: note: instantiated from:
diff --git a/test/PCH/cxx-alias-decl.cpp b/test/PCH/cxx-alias-decl.cpp
new file mode 100644
index 0000000..e30311c
--- /dev/null
+++ b/test/PCH/cxx-alias-decl.cpp
@@ -0,0 +1,20 @@
+// Test this without pch.
+// RUN: %clang_cc1 -x c++ -std=c++0x -include %S/cxx-alias-decl.h -fsyntax-only -emit-llvm -o - %s
+
+// Test with pch.
+// RUN: %clang_cc1 -x c++ -std=c++0x -emit-pch -o %t %S/cxx-alias-decl.h
+// RUN: %clang_cc1 -x c++ -std=c++0x -include-pch %t -fsyntax-only -emit-llvm -o - %s
+
+template struct T<S>;
+C<A>::A<char> a;
+
+using T1 = decltype(a);
+using T1 = D<int, char>;
+
+using T2 = B<A>;
+using T2 = S;
+
+using A = int;
+template<typename U> using B = S;
+template<typename U> using C = T<U>;
+template<typename U, typename V> using D = typename T<U>::template A<V>;
diff --git a/test/PCH/cxx-alias-decl.h b/test/PCH/cxx-alias-decl.h
new file mode 100644
index 0000000..26bc716
--- /dev/null
+++ b/test/PCH/cxx-alias-decl.h
@@ -0,0 +1,11 @@
+// Header for PCH test cxx-alias-decl.cpp
+
+struct S {};
+template<typename U> struct T {
+ template<typename V> using A = T<V>;
+};
+
+using A = int;
+template<typename U> using B = S;
+template<typename U> using C = T<U>;
+template<typename U, typename V> using D = typename T<U>::template A<V>;
diff --git a/test/PCH/cxx-for-range.cpp b/test/PCH/cxx-for-range.cpp
index 5854917..46e217c 100644
--- a/test/PCH/cxx-for-range.cpp
+++ b/test/PCH/cxx-for-range.cpp
@@ -1,9 +1,9 @@
// Test this without pch.
-// RUN: %clang_cc1 -std=c++0x -include %S/cxx-for-range.h -fsyntax-only -emit-llvm -o - %s
+// RUN: %clang_cc1 -x c++ -std=c++0x -include %S/cxx-for-range.h -fsyntax-only -emit-llvm -o - %s
// Test with pch.
-// RUN: %clang_cc1 -std=c++0x -emit-pch -o %t %S/cxx-for-range.h
-// RUN: %clang_cc1 -std=c++0x -include-pch %t -fsyntax-only -emit-llvm -o - %s
+// RUN: %clang_cc1 -x c++ -std=c++0x -emit-pch -o %t %S/cxx-for-range.h
+// RUN: %clang_cc1 -x c++ -std=c++0x -include-pch %t -fsyntax-only -emit-llvm -o - %s
void h() {
f();
diff --git a/test/PCH/cxx-member-init.cpp b/test/PCH/cxx-member-init.cpp
new file mode 100644
index 0000000..70392a2
--- /dev/null
+++ b/test/PCH/cxx-member-init.cpp
@@ -0,0 +1,22 @@
+// Test this without pch.
+// RUN: %clang_cc1 -x c++ -std=c++0x -DHEADER -DSOURCE -fsyntax-only -emit-llvm -o - %s
+
+// Test with pch.
+// RUN: %clang_cc1 -x c++ -std=c++0x -DHEADER -emit-pch -o %t %s
+// RUN: %clang_cc1 -x c++ -std=c++0x -DHEADER -include-pch %t -fsyntax-only -emit-llvm -o - %s
+
+#ifdef HEADER
+int n;
+struct S {
+ int *p = &m;
+ int &m = n;
+ S *that = this;
+};
+#endif
+
+#ifdef SOURCE
+S s;
+#elif HEADER
+#undef HEADER
+#define SOURCE
+#endif
diff --git a/test/PCH/cxx-reference.cpp b/test/PCH/cxx-reference.cpp
index 90d00d7..2dfbcdc 100644
--- a/test/PCH/cxx-reference.cpp
+++ b/test/PCH/cxx-reference.cpp
@@ -1,6 +1,6 @@
// Test this without pch.
-// RUN: %clang_cc1 -std=c++0x -include %S/cxx-reference.h -fsyntax-only -emit-llvm -o - %s
+// RUN: %clang_cc1 -x c++ -std=c++0x -include %S/cxx-reference.h -fsyntax-only -emit-llvm -o - %s
// Test with pch.
-// RUN: %clang_cc1 -std=c++0x -emit-pch -o %t %S/cxx-reference.h
-// RUN: %clang_cc1 -std=c++0x -include-pch %t -fsyntax-only -emit-llvm -o - %s
+// RUN: %clang_cc1 -x c++ -std=c++0x -emit-pch -o %t %S/cxx-reference.h
+// RUN: %clang_cc1 -x c++ -std=c++0x -include-pch %t -fsyntax-only -emit-llvm -o - %s
diff --git a/test/PCH/cxx-static_assert.cpp b/test/PCH/cxx-static_assert.cpp
index 3440921..464da40 100644
--- a/test/PCH/cxx-static_assert.cpp
+++ b/test/PCH/cxx-static_assert.cpp
@@ -1,11 +1,20 @@
// Test this without pch.
-// RUN: %clang_cc1 -include %S/cxx-static_assert.h -verify -std=c++0x %s
+// RUN: %clang_cc1 -include %s -verify -std=c++0x %s
// Test with pch.
-// RUN: %clang_cc1 -x c++-header -std=c++0x -emit-pch -o %t %S/cxx-static_assert.h
+// RUN: %clang_cc1 -std=c++0x -emit-pch -o %t %s
// RUN: %clang_cc1 -include-pch %t -verify -std=c++0x %s
-// expected-error {{static_assert failed "N is not 2!"}}
+#ifndef HEADER
+#define HEADER
+
+template<int N> struct T {
+ static_assert(N == 2, "N is not 2!"); // expected-error {{static_assert failed "N is not 2!"}}
+};
+
+#else
T<1> t1; // expected-note {{in instantiation of template class 'T<1>' requested here}}
T<2> t2;
+
+#endif
diff --git a/test/PCH/cxx-static_assert.h b/test/PCH/cxx-static_assert.h
deleted file mode 100644
index ba41ab8..0000000
--- a/test/PCH/cxx-static_assert.h
+++ /dev/null
@@ -1,9 +0,0 @@
-// Header for PCH test cxx-static_assert.cpp
-
-
-
-
-
-template<int N> struct T {
- static_assert(N == 2, "N is not 2!");
-};
diff --git a/test/PCH/cxx0x-default-delete.cpp b/test/PCH/cxx0x-default-delete.cpp
new file mode 100644
index 0000000..753ac47
--- /dev/null
+++ b/test/PCH/cxx0x-default-delete.cpp
@@ -0,0 +1,23 @@
+// Without PCH
+// RUN: %clang_cc1 -std=c++0x -fsyntax-only -verify -include %s %s
+// With PCH
+// RUN: %clang_cc1 -x c++-header -std=c++0x -emit-pch -o %t %s
+// RUN: %clang_cc1 -std=c++0x -fsyntax-only -verify -include-pch %t %s
+
+#ifndef PASS1
+#define PASS1
+
+struct foo {
+ foo() = default;
+ void bar() = delete; // expected-note{{deleted here}}
+};
+
+#else
+
+foo::foo() { } // expected-error{{definition of explicitly defaulted default constructor}}
+foo f;
+void fn() {
+ f.bar(); // expected-error{{deleted function}}
+}
+
+#endif
diff --git a/test/PCH/cxx0x-delegating-ctors.cpp b/test/PCH/cxx0x-delegating-ctors.cpp
new file mode 100644
index 0000000..15311f8
--- /dev/null
+++ b/test/PCH/cxx0x-delegating-ctors.cpp
@@ -0,0 +1,20 @@
+// Test this without pch.
+// RUN: %clang_cc1 -include %s -std=c++0x -fsyntax-only -verify %s
+
+// Test with pch.
+// RUN: %clang_cc1 -x c++-header -std=c++0x -emit-pch -o %t %s
+// RUN: %clang_cc1 -std=c++0x -include-pch %t -fsyntax-only -verify %s
+
+#ifndef PASS1
+#define PASS1
+struct foo {
+ foo(int) : foo() { } // expected-note{{it delegates to}}
+ foo();
+ foo(bool) : foo('c') { } // expected-note{{it delegates to}}
+ foo(char) : foo(true) { } // expected-error{{creates a delegation cycle}} \
+ // expected-note{{which delegates to}}
+};
+#else
+foo::foo() : foo(1) { } // expected-error{{creates a delegation cycle}} \
+ // expected-note{{which delegates to}}
+#endif
diff --git a/test/PCH/modified-header-error.c b/test/PCH/modified-header-error.c
new file mode 100644
index 0000000..6335fb1
--- /dev/null
+++ b/test/PCH/modified-header-error.c
@@ -0,0 +1,11 @@
+// RUN: mkdir -p %t.dir
+// RUN: echo '#include "header2.h"' > %t.dir/header1.h
+// RUN: echo > %t.dir/header2.h
+// RUN: cp %s %t.dir/t.c
+// RUN: %clang_cc1 -x c-header %t.dir/header1.h -emit-pch -o %t.pch
+// RUN: echo >> %t.dir/header2.h
+// RUN: %clang_cc1 %t.dir/t.c -include-pch %t.pch -fsyntax-only 2>&1 | FileCheck %s
+
+#include "header2.h"
+
+// CHECK: fatal error: file {{.*}} has been modified since the precompiled header was built
diff --git a/test/PCH/objc_methods.h b/test/PCH/objc_methods.h
index 4c6b1e1..bd77535 100644
--- a/test/PCH/objc_methods.h
+++ b/test/PCH/objc_methods.h
@@ -2,7 +2,7 @@
@interface TestPCH
+ alloc;
-- (void)instMethod;
+- (id)init;
@end
@class TestForwardClassDecl;
diff --git a/test/PCH/objc_methods.m b/test/PCH/objc_methods.m
index e90a463..3311813 100644
--- a/test/PCH/objc_methods.m
+++ b/test/PCH/objc_methods.m
@@ -12,5 +12,5 @@ void func() {
// AliasForTestPCH *zz;
xx = [TestPCH alloc];
- [xx instMethod];
+ [xx init];
}
diff --git a/test/PCH/objcxx-ivar-class.mm b/test/PCH/objcxx-ivar-class.mm
index 89d3e08..8214957 100644
--- a/test/PCH/objcxx-ivar-class.mm
+++ b/test/PCH/objcxx-ivar-class.mm
@@ -6,7 +6,7 @@
// RUN: %clang_cc1 -include-pch %t -verify %s -emit-llvm -o - | FileCheck %s
// CHECK: [C position]
-// CHECK: call void @_ZN1SC1ERKS_
+// CHECK: call {{.*}} @_ZN1SC1ERKS_
// CHECK: [C setPosition:]
// CHECK: call %struct.S* @_ZN1SaSERKS_
diff --git a/test/Parser/MicrosoftExtensions.cpp b/test/Parser/MicrosoftExtensions.cpp
index 32ed375..3a72ea0 100644
--- a/test/Parser/MicrosoftExtensions.cpp
+++ b/test/Parser/MicrosoftExtensions.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 %s -fsyntax-only -Wno-unused-value -Wmicrosoft -verify -fms-extensions
+// RUN: %clang_cc1 %s -fsyntax-only -Wno-unused-value -Wmicrosoft -verify -fms-extensions -fdelayed-template-parsing
/* Microsoft attribute tests */
[repeatable][source_annotation_attribute( Parameter|ReturnValue )]
@@ -105,6 +105,13 @@ template <class T, const GUID& g>
class COM_CLASS_TEMPLATE_REF { };
typedef COM_CLASS_TEMPLATE<struct_with_uuid, __uuidof(struct_with_uuid)> COM_TYPE_REF;
+ struct late_defined_uuid;
+ template<typename T>
+ void test_late_defined_uuid() {
+ __uuidof(late_defined_uuid);
+ }
+ struct __declspec(uuid("000000A0-0000-0000-C000-000000000049")) late_defined_uuid;
+
class CtorCall {
public:
@@ -136,7 +143,7 @@ class C2 {
};
template <class T>
-void f(){
+void missing_template_keyword(){
typename C1<T>:: /*template*/ Iterator<0> Mypos; // expected-warning {{use 'template' keyword to treat 'Iterator' as a dependent template name}}
}
@@ -151,11 +158,6 @@ void redundant_typename() {
t = 3;
}
-int main() {
- redundant_typename<int>();
- f<int>();
-}
-
__interface MicrosoftInterface;
__interface MicrosoftInterface {
@@ -164,3 +166,87 @@ __interface MicrosoftInterface {
};
__int64 x7 = __int64(0);
+
+
+namespace If_exists_test {
+
+class IF_EXISTS {
+private:
+ typedef int Type;
+};
+
+int __if_exists_test() {
+ int b=0;
+ __if_exists(IF_EXISTS::Type) {
+ b++;
+ b++;
+ }
+ __if_exists(IF_EXISTS::Type_not) {
+ this wont compile.
+ }
+ __if_not_exists(IF_EXISTS::Type) {
+ this wont compile.
+ }
+ __if_not_exists(IF_EXISTS::Type_not) {
+ b++;
+ b++;
+ }
+}
+
+
+__if_exists(IF_EXISTS::Type) {
+ int var23;
+}
+
+__if_exists(IF_EXISTS::Type_not) {
+ this wont compile.
+}
+
+__if_not_exists(IF_EXISTS::Type) {
+ this wont compile.
+}
+
+__if_not_exists(IF_EXISTS::Type_not) {
+ int var244;
+}
+
+class IF_EXISTS_CLASS_TEST {
+ __if_exists(IF_EXISTS::Type) {
+ // __if_exists, __if_not_exists can nest
+ __if_not_exists(IF_EXISTS::Type_not) {
+ int var123;
+ }
+ int var23;
+ }
+
+ __if_exists(IF_EXISTS::Type_not) {
+ this wont compile.
+ }
+
+ __if_not_exists(IF_EXISTS::Type) {
+ this wont compile.
+ }
+
+ __if_not_exists(IF_EXISTS::Type_not) {
+ int var244;
+ }
+};
+
+}
+
+
+int __identifier(generic) = 3;
+
+class inline_definition_pure_spec {
+ virtual int f() = 0 { return 0; }// expected-warning {{function definition with pure-specifier is a Microsoft extension}}
+ virtual int f2() = 0;
+};
+
+
+int main () {
+ // Necessary to force instantiation in -fdelayed-template-parsing mode.
+ test_late_defined_uuid<int>();
+ redundant_typename<int>();
+ missing_template_keyword<int>();
+}
+
diff --git a/test/Parser/cxx-default-delete.cpp b/test/Parser/cxx-default-delete.cpp
new file mode 100644
index 0000000..a3d5b2c
--- /dev/null
+++ b/test/Parser/cxx-default-delete.cpp
@@ -0,0 +1,15 @@
+// RUN: %clang_cc1 -std=c++0x -fsyntax-only -verify %s
+
+int i = delete; // expected-error{{only functions}}
+int j = default; // expected-error{{special member functions}}
+
+int f() = delete, g; // expected-error{{standalone}}
+int o, p() = delete; // expected-error{{standalone}}
+
+struct foo {
+ foo() = default;
+ ~foo() = delete;
+ void bar() = delete;
+};
+
+void baz() = delete;
diff --git a/test/Parser/cxx-ext-delete-default.cpp b/test/Parser/cxx-ext-delete-default.cpp
new file mode 100644
index 0000000..0627238
--- /dev/null
+++ b/test/Parser/cxx-ext-delete-default.cpp
@@ -0,0 +1,11 @@
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++98 %s
+
+struct A {
+ A(const A&) = delete; // expected-warning {{accepted as a C++0x extension}}
+ A& operator=(const A&) = delete; // expected-warning {{accepted as a C++0x extension}}
+ A() = default; // expected-warning {{accepted as a C++0x extension}}
+ ~A();
+};
+
+void f() = delete; // expected-warning {{accepted as a C++0x extension}}
+A::~A() = default; //expected-warning {{accepted as a C++0x extension}}
diff --git a/test/Parser/cxx-friend.cpp b/test/Parser/cxx-friend.cpp
index 59350b5..a13e7ba 100644
--- a/test/Parser/cxx-friend.cpp
+++ b/test/Parser/cxx-friend.cpp
@@ -21,9 +21,9 @@ class B {
// 'A' here should refer to the declaration above.
friend class A;
- friend C; // expected-warning {{must specify 'class' to befriend}}
- friend U; // expected-warning {{must specify 'union' to befriend}}
- friend int; // expected-warning {{non-class type 'int' cannot be a friend}}
+ friend C; // expected-warning {{specify 'class' to befriend}}
+ friend U; // expected-warning {{specify 'union' to befriend}}
+ friend int; // expected-warning {{non-class friend type 'int'}}
friend void myfunc();
diff --git a/test/Parser/cxx0x-member-initializers.cpp b/test/Parser/cxx0x-member-initializers.cpp
new file mode 100644
index 0000000..6c3492e
--- /dev/null
+++ b/test/Parser/cxx0x-member-initializers.cpp
@@ -0,0 +1,15 @@
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++0x %s
+
+// Make sure we don't run off the end of the stream when parsing a deferred
+// initializer.
+int a; // expected-note {{previous}}
+struct S {
+ int n = 4 + ; // expected-error {{expected expression}}
+} a; // expected-error {{redefinition}}
+
+// Make sure we use all of the tokens.
+struct T {
+ int a = 1 // expected-error {{expected ';' at end of declaration list}}
+ int b = 2;
+ int c = b; // expected-error {{undeclared identifier}}
+};
diff --git a/test/Parser/nested-namespaces-recovery.cpp b/test/Parser/nested-namespaces-recovery.cpp
new file mode 100644
index 0000000..d45938b
--- /dev/null
+++ b/test/Parser/nested-namespaces-recovery.cpp
@@ -0,0 +1,24 @@
+// RUN: cp %s %t
+// RUN: %clang_cc1 -fsyntax-only -verify %s
+// RUN: not %clang_cc1 -x c++ -fixit %t
+// RUN: %clang_cc1 -x c++ %t
+
+namespace foo1::foo2::foo3 { // expected-error {{nested namespace definition must define each namespace separately}}
+ int foo(int x) { return x; }
+}
+
+int foo(int x) {
+ return foo1::foo2::foo3::foo(x);
+}
+
+namespace bar1 {
+ namespace bar2 {
+ namespace bar3 {
+ int bar(int x) { return x; }
+ }
+ }
+}
+
+int bar(int x) {
+ return bar1::bar2::bar3::bar(x);
+}
diff --git a/test/Parser/opencl-astype.cl b/test/Parser/opencl-astype.cl
new file mode 100644
index 0000000..d4c547e
--- /dev/null
+++ b/test/Parser/opencl-astype.cl
@@ -0,0 +1,20 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s
+#pragma OPENCL EXTENSION cl_khr_fp64 : enable
+
+void test_astype() {
+ float f = 1.0f;
+ unsigned int i = __builtin_astype(f, unsigned int);
+
+ typedef __attribute__(( ext_vector_type(4) )) int int4;
+ typedef __attribute__(( ext_vector_type(3) )) float float3;
+ typedef __attribute__(( ext_vector_type(4) )) float float4;
+ typedef __attribute__(( ext_vector_type(4) )) double double4;
+
+ float4 f4;
+ double4 d4 = __builtin_astype(f4, double4); // expected-error{{invalid reinterpretation: sizes of 'double4' and 'float4' must match}}
+
+ // Verify int4->float3, float3->int4 works.
+ int4 i4;
+ float3 f3 = __builtin_astype(i4, float3);
+ i4 = __builtin_astype(f3, int4);
+}
diff --git a/test/Preprocessor/if_warning.c b/test/Preprocessor/if_warning.c
index 345ac95..641ec3b 100644
--- a/test/Preprocessor/if_warning.c
+++ b/test/Preprocessor/if_warning.c
@@ -20,6 +20,10 @@ extern int x;
#endif
#endif
+// rdar://9475098
+#if 0
+#else 1 // expected-warning {{extra tokens}}
+#endif
// PR6852
#if 'somesillylongthing' // expected-warning {{character constant too long for its type}} \
diff --git a/test/Preprocessor/pragma_sysheader.c b/test/Preprocessor/pragma_sysheader.c
index cf2843b..2641682 100644
--- a/test/Preprocessor/pragma_sysheader.c
+++ b/test/Preprocessor/pragma_sysheader.c
@@ -1,3 +1,12 @@
// RUN: %clang -verify -pedantic %s -fsyntax-only
+// RUN: %clang_cc1 -E %s | FileCheck %s
// rdar://6899937
#include "pragma_sysheader.h"
+
+
+// PR9861: Verify that line markers are not messed up in -E mode.
+// CHECK: # 1 "{{.*}}pragma_sysheader.h" 1
+// CHECK-NEXT: # 1 "{{.*}}pragma_sysheader.h" 3
+// CHECK-NEXT: typedef int x;
+// CHECK-NEXT: typedef int x;
+// CHECK-NEXT: # 5 "{{.*}}pragma_sysheader.c" 2
diff --git a/test/Sema/MicrosoftExtensions.c b/test/Sema/MicrosoftExtensions.c
index cb9fee9..7438f7f5 100644
--- a/test/Sema/MicrosoftExtensions.c
+++ b/test/Sema/MicrosoftExtensions.c
@@ -79,3 +79,11 @@ struct X0 {
enum : long long { // expected-warning{{enumeration types with a fixed underlying type are a Microsoft extension}}
SomeValue = 0x100000000
};
+
+
+void pointer_to_integral_type_conv(char* ptr) {
+ char ch = (char)ptr;
+ short sh = (short)ptr;
+ ch = (char)ptr;
+ sh = (short)ptr;
+}
diff --git a/test/Sema/arm-neon-types.c b/test/Sema/arm-neon-types.c
index 152d4c9..1e8c9bf 100644
--- a/test/Sema/arm-neon-types.c
+++ b/test/Sema/arm-neon-types.c
@@ -9,5 +9,12 @@ int32x2_t test(int32x2_t x) {
// ...but should warn when the types really do not match.
float32x2_t test2(uint32x2_t x) {
- return vcvt_n_f32_s32(x, 0); // expected-warning {{incompatible vector types}}
+ return vcvt_n_f32_s32(x, 9); // expected-warning {{incompatible vector types}}
+}
+
+// Check immediate range for vcvt_n intrinsics is 1 to 32. Radar 9558930.
+float32x2_t test3(uint32x2_t x) {
+ // FIXME: The "incompatible result type" error is due to pr10112 and should be
+ // removed when that is fixed.
+ return vcvt_n_f32_u32(x, 0); // expected-error {{argument should be a value from 1 to 32}} expected-error {{incompatible result type}}
}
diff --git a/test/Sema/asm.c b/test/Sema/asm.c
index 7f0f396..d8161c8 100644
--- a/test/Sema/asm.c
+++ b/test/Sema/asm.c
@@ -105,3 +105,11 @@ void test10(void){
register int r asm ("cx");
register int rr asm ("rr_asm"); // expected-error{{unknown register name 'rr_asm' in asm}}
}
+
+// This is just an assert because of the boolean conversion.
+// Feel free to change the assembly to something sensible if it causes a problem.
+// rdar://problem/9414925
+void test11(void) {
+ _Bool b;
+ asm volatile ("movb %%gs:%P2,%b0" : "=q"(b) : "0"(0), "i"(5L));
+}
diff --git a/test/Sema/attr-unknown.c b/test/Sema/attr-unknown.c
index bec2e29..d1a831d 100644
--- a/test/Sema/attr-unknown.c
+++ b/test/Sema/attr-unknown.c
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -verify -Wunknown-attributes %s
+// RUN: %clang_cc1 -fsyntax-only -verify -Wattributes %s
int x __attribute__((foobar)); // expected-warning {{unknown attribute 'foobar' ignored}}
void z() __attribute__((bogusattr)); // expected-warning {{unknown attribute 'bogusattr' ignored}}
diff --git a/test/Sema/builtins-arm.c b/test/Sema/builtins-arm.c
index 4dd31e7..4077240 100644
--- a/test/Sema/builtins-arm.c
+++ b/test/Sema/builtins-arm.c
@@ -9,3 +9,8 @@ void __clear_cache(char*, char*);
void __clear_cache(void*, void*);
#endif
+// va_list on ARM is void*.
+void test2() {
+ __builtin_va_list ptr = "x";
+ *ptr = '0'; // expected-error {{incomplete type 'void' is not assignable}}
+}
diff --git a/test/Sema/carbon.c b/test/Sema/carbon.c
index f0affd2..045d72c 100644
--- a/test/Sema/carbon.c
+++ b/test/Sema/carbon.c
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -target-cpu pentium4 %s -print-stats
+// RUN: %clang -fsyntax-only %s -print-stats
#ifdef __APPLE__
#include <Carbon/Carbon.h>
#endif
diff --git a/test/Sema/exprs.c b/test/Sema/exprs.c
index e4eeaec..9ce1481 100644
--- a/test/Sema/exprs.c
+++ b/test/Sema/exprs.c
@@ -189,6 +189,24 @@ int test20(int x) {
// no warning, this is an idiom for "true" in old C style.
return x && (signed char)1;
+
+ return x || 0;
+ return x || 1;
+ return x || -1; // expected-warning {{use of logical || with constant operand; switch to bitwise | or remove constant}}
+ return x || 5; // expected-warning {{use of logical || with constant operand; switch to bitwise | or remove constant}}
+ return x && 0;
+ return x && 1;
+ return x && -1; // expected-warning {{use of logical && with constant operand; switch to bitwise & or remove constant}}
+ return x && 5; // expected-warning {{use of logical && with constant operand; switch to bitwise & or remove constant}}
+ return x || (0);
+ return x || (1);
+ return x || (-1); // expected-warning {{use of logical || with constant operand; switch to bitwise | or remove constant}}
+ return x || (5); // expected-warning {{use of logical || with constant operand; switch to bitwise | or remove constant}}
+ return x && (0);
+ return x && (1);
+ return x && (-1); // expected-warning {{use of logical && with constant operand; switch to bitwise & or remove constant}}
+ return x && (5); // expected-warning {{use of logical && with constant operand; switch to bitwise & or remove constant}}
+
}
struct Test21; // expected-note 2 {{forward declaration}}
diff --git a/test/Sema/illegal-types.c b/test/Sema/illegal-types.c
index 3c59df8..819b38a 100644
--- a/test/Sema/illegal-types.c
+++ b/test/Sema/illegal-types.c
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -verify -std=c++98 %s
+// RUN: %clang_cc1 -fsyntax-only -verify -x c++ -std=c++98 %s
void a (void []()); // expected-error{{'type name' declared as array of functions}}
void b (void p[]()); // expected-error{{'p' declared as array of functions}}
diff --git a/test/Sema/parentheses.c b/test/Sema/parentheses.c
index a25ded6..fa3c3c2 100644
--- a/test/Sema/parentheses.c
+++ b/test/Sema/parentheses.c
@@ -39,6 +39,28 @@ void bitwise_rel(unsigned i) {
(void)(0 || i && i); // no warning.
}
+_Bool someConditionFunc();
+
+void conditional_op(int x, int y, _Bool b) {
+ (void)(x + someConditionFunc() ? 1 : 2); // expected-warning {{?: has lower precedence than +}} \
+ // expected-note {{place parentheses around the ?: expression to evaluate it first}} \
+ // expected-note {{place parentheses around the + expression to silence this warning}}
+
+ (void)(x - b ? 1 : 2); // expected-warning {{?: has lower precedence than -}} \
+ // expected-note {{place parentheses around the ?: expression to evaluate it first}} \
+ // expected-note {{place parentheses around the - expression to silence this warning}}
+
+ (void)(x * (x == y) ? 1 : 2); // expected-warning {{?: has lower precedence than *}} \
+ // expected-note {{place parentheses around the ?: expression to evaluate it first}} \
+ // expected-note {{place parentheses around the * expression to silence this warning}}
+
+ (void)(x / !x ? 1 : 2); // expected-warning {{?: has lower precedence than /}} \
+ // expected-note {{place parentheses around the ?: expression to evaluate it first}} \
+ // expected-note {{place parentheses around the / expression to silence this warning}}
+
+
+ (void)(x % 2 ? 1 : 2); // no warning
+}
+
// RUN: %clang_cc1 -fsyntax-only -Wparentheses -Werror -fdiagnostics-show-option %s 2>&1 | FileCheck %s
// CHECK: error: using the result of an assignment as a condition without parentheses [-Werror,-Wparentheses]
-
diff --git a/test/Sema/parentheses.cpp b/test/Sema/parentheses.cpp
new file mode 100644
index 0000000..a25f2a0
--- /dev/null
+++ b/test/Sema/parentheses.cpp
@@ -0,0 +1,31 @@
+// RUN: %clang_cc1 -Wparentheses -fsyntax-only -verify %s
+// RUN: %clang_cc1 -Wparentheses -fixit %s -o - | %clang_cc1 -Wparentheses -Werror -
+
+bool someConditionFunc();
+
+void conditional_op(int x, int y, bool b) {
+ (void)(x + someConditionFunc() ? 1 : 2); // expected-warning {{?: has lower precedence than +}} \
+ // expected-note {{place parentheses around the ?: expression to evaluate it first}} \
+ // expected-note {{place parentheses around the + expression to silence this warning}}
+
+ (void)(x - b ? 1 : 2); // expected-warning {{?: has lower precedence than -}} \
+ // expected-note {{place parentheses around the ?: expression to evaluate it first}} \
+ // expected-note {{place parentheses around the - expression to silence this warning}}
+
+ (void)(x * (x == y) ? 1 : 2); // expected-warning {{?: has lower precedence than *}} \
+ // expected-note {{place parentheses around the ?: expression to evaluate it first}} \
+ // expected-note {{place parentheses around the * expression to silence this warning}}
+}
+
+class Stream {
+public:
+ operator int();
+ Stream &operator<<(int);
+ Stream &operator<<(const char*);
+};
+
+void f(Stream& s, bool b) {
+ (void)(s << b ? "foo" : "bar"); // expected-warning {{?: has lower precedence than <<}} \
+ // expected-note {{place parentheses around the ?: expression to evaluate it first}} \
+ // expected-note {{place parentheses around the << expression to silence this warning}}
+}
diff --git a/test/Sema/stdcall-fastcall.c b/test/Sema/stdcall-fastcall.c
index 4531eb2..eeacf94 100644
--- a/test/Sema/stdcall-fastcall.c
+++ b/test/Sema/stdcall-fastcall.c
@@ -1,4 +1,5 @@
-// RUN: %clang_cc1 -fsyntax-only -verify %s
+// RUN: %clang_cc1 -fsyntax-only -verify -triple x86_64-pc-linux-gnu %s
+// RUN: %clang_cc1 -fsyntax-only -verify -triple i686-apple-darwin10 %s
// CC qualifier can be applied only to functions
int __attribute__((stdcall)) var1; // expected-warning{{'stdcall' only applies to function types; type here is 'int'}}
diff --git a/test/Sema/uninit-variables.c b/test/Sema/uninit-variables.c
index 60cae80..b70a295 100644
--- a/test/Sema/uninit-variables.c
+++ b/test/Sema/uninit-variables.c
@@ -339,3 +339,16 @@ int test51(void)
return a; // no-warning
}
+// FIXME: This is a false positive, but it tests logical operations in switch statements.
+int test52(int a, int b) {
+ int x; // expected-note {{variable 'x' is declared here}} expected-note {{add initialization to silence this warning}}
+ switch (a || b) { // expected-warning {{switch condition has boolean value}}
+ case 0:
+ x = 1;
+ break;
+ case 1:
+ x = 2;
+ break;
+ }
+ return x; // expected-warning {{variable 'x' may be uninitialized when used here}}
+}
diff --git a/test/Sema/x86-builtin-palignr.c b/test/Sema/x86-builtin-palignr.c
index 2344306..83719a3 100644
--- a/test/Sema/x86-builtin-palignr.c
+++ b/test/Sema/x86-builtin-palignr.c
@@ -1,4 +1,5 @@
-// RUN: %clang_cc1 -ffreestanding -fsyntax-only -target-feature +ssse3 -verify %s
+// RUN: %clang_cc1 -ffreestanding -fsyntax-only -target-feature +ssse3 -verify -triple x86_64-pc-linux-gnu %s
+// RUN: %clang_cc1 -ffreestanding -fsyntax-only -target-feature +ssse3 -verify -triple i686-apple-darwin10 %s
#include <tmmintrin.h>
diff --git a/test/SemaCXX/MicrosoftExtensions.cpp b/test/SemaCXX/MicrosoftExtensions.cpp
index 2d620b6..9b03feb 100644
--- a/test/SemaCXX/MicrosoftExtensions.cpp
+++ b/test/SemaCXX/MicrosoftExtensions.cpp
@@ -6,6 +6,8 @@ void f(const type_info &a);
// Microsoft doesn't validate exception specification.
+namespace microsoft_exception_spec {
+
void foo(); // expected-note {{previous declaration}}
void foo() throw(); // expected-warning {{exception specification in declaration does not match previous declaration}}
@@ -22,6 +24,15 @@ struct Derived : Base {
virtual void f3();
};
+class A {
+ virtual ~A() throw(); // expected-note {{overridden virtual function is here}}
+};
+
+class B : public A {
+ virtual ~B(); // expected-warning {{exception specification of overriding function is more lax than base version}}
+};
+
+}
// MSVC allows type definition in anonymous union and struct
struct A
@@ -179,4 +190,65 @@ void static_func(); // expected-note {{previous declaration is here}}
static void static_func() // expected-warning {{static declaration of 'static_func' follows non-static declaration}}
{
-} \ No newline at end of file
+}
+
+long function_prototype(int a);
+long (*function_ptr)(int a);
+
+void function_to_voidptr_conv() {
+ void *a1 = function_prototype;
+ void *a2 = &function_prototype;
+ void *a3 = function_ptr;
+}
+
+
+void pointer_to_integral_type_conv(char* ptr) {
+ char ch = (char)ptr;
+ short sh = (short)ptr;
+ ch = (char)ptr;
+ sh = (short)ptr;
+}
+
+namespace ms_using_declaration_bug {
+
+class A {
+public:
+ int f();
+};
+
+class B : public A {
+private:
+ using A::f;
+};
+
+class C : public B {
+private:
+ using B::f; // expected-warning {{using declaration refers to inaccessible member 'ms_using_declaration_bug::B::f', which refers to accessible member 'ms_using_declaration_bug::A::f', accepted for Microsoft compatibility}}
+};
+
+}
+
+
+
+namespace friend_as_a_forward_decl {
+
+class A {
+ class Nested {
+ friend class B;
+ B* b;
+ };
+ B* b;
+};
+B* global_b;
+
+
+void f()
+{
+ class Local {
+ friend class Z;
+ Z* b;
+ };
+ Z* b;
+}
+
+ } \ No newline at end of file
diff --git a/test/SemaCXX/PR9572.cpp b/test/SemaCXX/PR9572.cpp
index d1b7077..25c0c01 100644
--- a/test/SemaCXX/PR9572.cpp
+++ b/test/SemaCXX/PR9572.cpp
@@ -1,13 +1,13 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s
class Base {
- virtual ~Base();
+ virtual ~Base(); // expected-note {{implicitly declared private here}}
};
-struct Foo : public Base {
- const int kBlah = 3; // expected-error{{fields can only be initialized in constructors}}
+struct Foo : public Base { // expected-error {{base class 'Base' has private destructor}}
+ const int kBlah = 3; // expected-warning {{accepted as a C++0x extension}}
Foo();
};
struct Bar : public Foo {
- Bar() { }
+ Bar() { } // expected-note {{implicit default destructor for 'Foo' first required here}}
};
struct Baz {
Foo f;
diff --git a/test/SemaCXX/PR9884.cpp b/test/SemaCXX/PR9884.cpp
new file mode 100644
index 0000000..ab883c4
--- /dev/null
+++ b/test/SemaCXX/PR9884.cpp
@@ -0,0 +1,17 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s
+class Base {
+protected:
+ Base(int val);
+};
+
+
+class Derived : public Base {
+public:
+ Derived(int val);
+};
+
+
+Derived::Derived(int val)
+ : Base( val )
+{
+}
diff --git a/test/SemaCXX/PR9902.cpp b/test/SemaCXX/PR9902.cpp
new file mode 100644
index 0000000..ec76789
--- /dev/null
+++ b/test/SemaCXX/PR9902.cpp
@@ -0,0 +1,28 @@
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++0x %s
+
+template <class _Tp, class _Up, bool = false>
+struct __allocator_traits_rebind
+{
+};
+
+template <template <class, class...> class _Alloc, class _Tp, class ..._Args,
+class _Up>
+struct __allocator_traits_rebind<_Alloc<_Tp, _Args...>, _Up, false>
+{
+ typedef _Alloc<_Up, _Args...> type;
+};
+
+template <class Alloc>
+struct allocator_traits
+{
+ template <class T> using rebind_alloc = typename __allocator_traits_rebind<Alloc, T>::type;
+ template <class T> using rebind_traits = allocator_traits<rebind_alloc<T>>;
+};
+
+template <class T>
+struct allocator {};
+
+int main()
+{
+ allocator_traits<allocator<char>>::rebind_alloc<int> a;
+}
diff --git a/test/SemaCXX/PR9908.cpp b/test/SemaCXX/PR9908.cpp
new file mode 100644
index 0000000..3b98b72
--- /dev/null
+++ b/test/SemaCXX/PR9908.cpp
@@ -0,0 +1,32 @@
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++0x %s
+
+template <class _Tp, class _Up>
+struct __allocator_traits_rebind
+{
+ typedef typename _Tp::template rebind<_Up>::other type;
+};
+
+template <class Alloc>
+struct allocator_traits
+{
+ typedef Alloc allocator_type;
+ template <class T> using rebind_alloc = typename
+__allocator_traits_rebind<allocator_type, T>::type;
+ template <class T> using rebind_traits = allocator_traits<rebind_alloc<T>>;
+};
+
+template <class T>
+struct ReboundA {};
+
+template <class T>
+struct A
+{
+ typedef T value_type;
+
+ template <class U> struct rebind {typedef ReboundA<U> other;};
+};
+
+int main()
+{
+ allocator_traits<A<char> >::rebind_traits<double> a;
+}
diff --git a/test/SemaCXX/aggregate-initialization.cpp b/test/SemaCXX/aggregate-initialization.cpp
index 4c34447..b9e69b0 100644
--- a/test/SemaCXX/aggregate-initialization.cpp
+++ b/test/SemaCXX/aggregate-initialization.cpp
@@ -2,6 +2,8 @@
// Verify that we can't initialize non-aggregates with an initializer
// list.
+// FIXME: Note that due to a (likely) standard bug, this is technically an
+// aggregate.
struct NonAggr1 {
NonAggr1(int) { }
@@ -22,7 +24,7 @@ struct NonAggr4 {
virtual void f();
};
-NonAggr1 na1 = { 17 }; // expected-error{{non-aggregate type 'NonAggr1' cannot be initialized with an initializer list}}
+NonAggr1 na1 = { 17 };
NonAggr2 na2 = { 17 }; // expected-error{{non-aggregate type 'NonAggr2' cannot be initialized with an initializer list}}
NonAggr3 na3 = { 17 }; // expected-error{{non-aggregate type 'NonAggr3' cannot be initialized with an initializer list}}
NonAggr4 na4 = { 17 }; // expected-error{{non-aggregate type 'NonAggr4' cannot be initialized with an initializer list}}
diff --git a/test/SemaCXX/alias-template.cpp b/test/SemaCXX/alias-template.cpp
new file mode 100644
index 0000000..f29a932
--- /dev/null
+++ b/test/SemaCXX/alias-template.cpp
@@ -0,0 +1,147 @@
+// RUN: %clang_cc1 -verify -std=c++0x %s
+
+namespace RedeclAliasTypedef {
+ template<typename U> using T = int;
+ template<typename U> using T = int;
+ template<typename U> using T = T<U>;
+}
+
+namespace IllegalTypeIds {
+ template<typename U> using A = void(int n = 0); // expected-error {{default arguments can only be specified for parameters in a function declaration}}
+ template<typename U> using B = inline void(int n); // expected-error {{type name does not allow function specifier}}
+ template<typename U> using C = virtual void(int n); // expected-error {{type name does not allow function specifier}}
+ template<typename U> using D = explicit void(int n); // expected-error {{type name does not allow function specifier}}
+ template<typename U> using E = void(int n) throw(); // expected-error {{exception specifications are not allowed in type aliases}}
+ // FIXME: this is illegal; we incorrectly accept it for typedefs too.
+ template<typename U> using F = void(*)(int n) &&; // expected-err
+ template<typename U> using G = __thread void(int n); // expected-error {{type name does not allow storage class to be specified}}
+
+ template<typename U> using H = void(int n); // ok
+ template<typename U> using I = void(int n) &&; // ok
+}
+
+namespace IllegalSyntax {
+ template<typename Z> using ::T = void(int n); // expected-error {{name defined in alias declaration must be an identifier}}
+ template<typename Z> using operator int = void(int n); // expected-error {{name defined in alias declaration must be an identifier}}
+ template<typename Z> using typename U = void; // expected-error {{name defined in alias declaration must be an identifier}}
+ template<typename Z> using typename ::V = void(int n); // expected-error {{name defined in alias declaration must be an identifier}}
+ template<typename Z> using typename ::operator bool = void(int n); // expected-error {{name defined in alias declaration must be an identifier}}
+}
+
+namespace VariableLengthArrays {
+ template<typename Z> using T = int[42]; // ok
+
+ int n = 32;
+ template<typename Z> using T = int[n]; // expected-error {{variable length array declaration not allowed at file scope}}
+
+ const int m = 42;
+ template<typename Z> using U = int[m]; // expected-note {{previous definition}}
+ template<typename Z> using U = int[42]; // ok
+ template<typename Z> using U = int; // expected-error {{type alias template redefinition with different types ('int' vs 'int [42]')}}
+}
+
+namespace RedeclFunc {
+ int f(int, char**);
+ template<typename Z> using T = int;
+ T<char> f(int, char **); // ok
+}
+
+namespace LookupFilter {
+ namespace N { template<typename U> using S = int; }
+ using namespace N;
+ template<typename U> using S = S<U>*; // ok
+}
+
+namespace InFunctions {
+ template<typename...T> struct S0 {
+ template<typename Z> using U = T*; // expected-error {{declaration type contains unexpanded parameter pack 'T'}}
+ U<char> u;
+ };
+
+ template<typename Z> using T1 = int;
+ template<typename Z> using T2 = int[-1]; // expected-error {{array size is negative}}
+ template<typename...T> struct S3 { // expected-note {{template parameter is declared here}}
+ template<typename Z> using T = int; // expected-error {{declaration of 'T' shadows template parameter}}
+ };
+ template<typename Z> using Z = Z;
+}
+
+namespace ClassNameRedecl {
+ class C0 {
+ // FIXME: this diagnostic is pretty poor
+ template<typename U> using C0 = int; // expected-error {{name defined in alias declaration must be an identifier}}
+ };
+ class C1 {
+ // FIXME: this diagnostic is pretty poor
+ template<typename U> using C1 = C1; // expected-error {{name defined in alias declaration must be an identifier}}
+ };
+ class C2 {
+ template<typename U> using C0 = C1; // ok
+ };
+ template<typename...T> class C3 {
+ template<typename U> using f = T; // expected-error {{declaration type contains unexpanded parameter pack 'T'}}
+ };
+ template<typename T> class C4 { // expected-note {{template parameter is declared here}}
+ template<typename U> using T = int; // expected-error {{declaration of 'T' shadows template parameter}}
+ };
+ class C5 {
+ class c; // expected-note {{previous definition}}
+ template<typename U> using c = int; // expected-error {{redefinition of 'c' as different kind of symbol}}
+ class d; // expected-note {{previous definition}}
+ template<typename U> using d = d; // expected-error {{redefinition of 'd' as different kind of symbol}}
+ };
+ class C6 {
+ class c { template<typename U> using C6 = int; }; // ok
+ };
+}
+
+class CtorDtorName {
+ template<typename T> using X = CtorDtorName;
+ X<int>(); // expected-error {{expected member name}}
+ ~X<int>(); // expected-error {{destructor cannot be declared using a type alias}}
+};
+
+namespace TagName {
+ template<typename Z> using S = struct { int n; }; // expected-error {{can not be defined}}
+ template<typename Z> using T = class { int n; }; // expected-error {{can not be defined}}
+ template<typename Z> using U = enum { a, b, c }; // expected-error {{can not be defined}}
+ template<typename Z> using V = struct V { int n; }; // expected-error {{redefinition of 'V' as different kind of symbol}} \
+ expected-error {{'TagName::V' can not be defined in a type alias template}} \
+ expected-note {{previous definition is here}}
+}
+
+namespace StdExample {
+ template<typename T, typename U> struct pair;
+
+ template<typename T> using handler_t = void (*)(T);
+ extern handler_t<int> ignore;
+ extern void (*ignore)(int);
+ // FIXME: we recover as if cell is an undeclared variable. the diagnostics are terrible!
+ template<typename T> using cell = pair<T*, cell<T>*>; // expected-error {{use of undeclared identifier 'cell'}} \
+ expected-error {{'T' does not refer to a value}} \
+ expected-note {{declared here}} \
+ expected-error {{expected ';' after alias declaration}}
+}
+
+namespace Access {
+ class C0 {
+ template<typename Z> using U = int; // expected-note {{declared private here}}
+ };
+ C0::U<int> v; // expected-error {{'U' is a private member}}
+ class C1 {
+ public:
+ template<typename Z> using U = int;
+ };
+ C1::U<int> w; // ok
+}
+
+namespace VoidArg {
+ template<typename Z> using V = void;
+ V<int> f(int); // ok
+ V<char> g(V<double>); // expected-error {{empty parameter list defined with a type alias of 'void' not allowed}}
+}
+
+namespace Curried {
+ template<typename T, typename U> struct S;
+ template<typename T> template<typename U> using SS = S<T, U>; // expected-error {{extraneous template parameter list in alias template declaration}}
+}
diff --git a/test/SemaCXX/anonymous-union.cpp b/test/SemaCXX/anonymous-union.cpp
index 553ae65..2dd7ab8 100644
--- a/test/SemaCXX/anonymous-union.cpp
+++ b/test/SemaCXX/anonymous-union.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -verify %s
+// RUN: %clang_cc1 -fsyntax-only -verify -pedantic %s
struct X {
union {
float f3;
@@ -17,7 +17,7 @@ struct X {
void test_unqual_references();
- struct {
+ struct { // expected-warning{{anonymous structs are a GNU extension}}
int a;
float b;
};
@@ -125,7 +125,7 @@ typedef struct _s {
// <rdar://problem/7987650>
namespace test4 {
class A {
- struct {
+ struct { // expected-warning{{anonymous structs are a GNU extension}}
int s0; // expected-note {{declared private here}}
double s1; // expected-note {{declared private here}}
union {
@@ -136,7 +136,7 @@ namespace test4 {
union {
int u0; // expected-note {{declared private here}}
double u1; // expected-note {{declared private here}}
- struct {
+ struct { // expected-warning{{anonymous structs are a GNU extension}}
int us0; // expected-note {{declared private here}}
double us1; // expected-note {{declared private here}}
};
@@ -175,3 +175,25 @@ void foo_PR6741() {
};
}
}
+
+namespace PR8326 {
+ template <class T>
+ class Foo {
+ public:
+ Foo()
+ : x(0)
+ , y(1){
+ }
+
+ private:
+ const union { // expected-warning{{anonymous union cannot be 'const'}}
+ struct { // expected-warning{{anonymous structs are a GNU extension}}
+ T x;
+ T y;
+ };
+ T v[2];
+ };
+ };
+
+ Foo<int> baz;
+}
diff --git a/test/SemaCXX/attr-cxx0x.cpp b/test/SemaCXX/attr-cxx0x.cpp
index 40fe0e0..725f018 100644
--- a/test/SemaCXX/attr-cxx0x.cpp
+++ b/test/SemaCXX/attr-cxx0x.cpp
@@ -9,8 +9,13 @@ struct align_member {
int member [[align(8)]];
};
+typedef char align_typedef [[align(8)]];
+template<typename T> using align_alias_template = align_typedef;
+
static_assert(alignof(align_big) == alignof(int), "k's alignment is wrong");
static_assert(alignof(align_small) == 1, "j's alignment is wrong");
static_assert(alignof(align_multiple) == 8, "l's alignment is wrong");
static_assert(alignof(align_member) == 8, "quuux's alignment is wrong");
static_assert(sizeof(align_member) == 8, "quuux's size is wrong");
+static_assert(alignof(align_typedef) == 8, "typedef's alignment is wrong");
+static_assert(alignof(align_alias_template<int>) == 8, "alias template's alignment is wrong");
diff --git a/test/SemaCXX/attr-noreturn.cpp b/test/SemaCXX/attr-noreturn.cpp
index b7d3999..eaf0d0c 100644
--- a/test/SemaCXX/attr-noreturn.cpp
+++ b/test/SemaCXX/attr-noreturn.cpp
@@ -1,5 +1,22 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s
+// Reachability tests have to come first because they get suppressed
+// if any errors have occurred.
+namespace test5 {
+ struct A {
+ __attribute__((noreturn)) void fail();
+ void nofail();
+ } a;
+
+ int &test1() {
+ a.nofail();
+ } // expected-warning {{control reaches end of non-void function}}
+
+ int &test2() {
+ a.fail();
+ }
+}
+
// PR5620
void f0() __attribute__((__noreturn__));
void f1(void (*)());
diff --git a/test/SemaCXX/attr-regparm.cpp b/test/SemaCXX/attr-regparm.cpp
index b98631a..91ee613 100644
--- a/test/SemaCXX/attr-regparm.cpp
+++ b/test/SemaCXX/attr-regparm.cpp
@@ -1,4 +1,5 @@
-// RUN: %clang_cc1 -fsyntax-only -verify %s
+// RUN: %clang_cc1 -fsyntax-only -verify -triple x86_64-pc-linux-gnu %s
+// RUN: %clang_cc1 -fsyntax-only -verify -triple i686-apple-darwin10 %s
// PR7025
struct X0 {
diff --git a/test/SemaCXX/class.cpp b/test/SemaCXX/class.cpp
index 52140cb..44fa0ce 100644
--- a/test/SemaCXX/class.cpp
+++ b/test/SemaCXX/class.cpp
@@ -34,7 +34,7 @@ public:
enum E1 { en1, en2 };
- int i = 0; // expected-error {{fields can only be initialized in constructors}}
+ int i = 0; // expected-warning {{in-class initialization of non-static data member accepted as a C++0x extension}}
static int si = 0; // expected-error {{non-const static data member must be initialized out of line}}
static const NestedC ci = 0; // expected-error {{static data member of type 'const C::NestedC' must be initialized out of line}}
static const int nci = vs; // expected-error {{in-class initializer is not a constant expression}}
diff --git a/test/SemaCXX/conversion.cpp b/test/SemaCXX/conversion.cpp
index fdda7ac..b069abc 100644
--- a/test/SemaCXX/conversion.cpp
+++ b/test/SemaCXX/conversion.cpp
@@ -1,5 +1,7 @@
// RUN: %clang_cc1 -triple x86_64-apple-darwin -fsyntax-only -Wconversion -verify %s
+#include <stddef.h>
+
typedef signed char int8_t;
typedef signed short int16_t;
typedef signed int int32_t;
@@ -50,3 +52,12 @@ namespace test2 {
A() : x(10) {} // expected-warning {{implicit truncation from 'int' to bitfield changes value from 10 to 2}}
};
}
+
+void test3() {
+ int a = NULL; // expected-warning {{implicit conversion of NULL constant to integer}}
+ int b;
+ b = NULL; // expected-warning {{implicit conversion of NULL constant to integer}}
+ int c = ((((NULL)))); // expected-warning {{implicit conversion of NULL constant to integer}}
+ int d;
+ d = ((((NULL)))); // expected-warning {{implicit conversion of NULL constant to integer}}
+}
diff --git a/test/SemaCXX/copy-constructor-error.cpp b/test/SemaCXX/copy-constructor-error.cpp
index 9809bfc..64a7d58 100644
--- a/test/SemaCXX/copy-constructor-error.cpp
+++ b/test/SemaCXX/copy-constructor-error.cpp
@@ -13,10 +13,10 @@ void g() {
namespace PR6064 {
struct A {
A() { }
- inline A(A&, int);
+ inline A(A&, int); // expected-note {{was not a special member function}}
};
- A::A(A&, int = 0) { }
+ A::A(A&, int = 0) { } // expected-warning {{makes this constructor a copy constructor}}
void f() {
A const a;
diff --git a/test/SemaCXX/cxx0x-cursory-default-delete.cpp b/test/SemaCXX/cxx0x-cursory-default-delete.cpp
new file mode 100644
index 0000000..61aee0e
--- /dev/null
+++ b/test/SemaCXX/cxx0x-cursory-default-delete.cpp
@@ -0,0 +1,69 @@
+// RUN: %clang_cc1 -std=c++0x -fsyntax-only -verify %s
+
+struct non_copiable {
+ non_copiable(const non_copiable&) = delete; // expected-note {{marked deleted here}}
+ non_copiable& operator = (const non_copiable&) = delete; // expected-note {{explicitly deleted}}
+ non_copiable() = default;
+};
+
+struct non_const_copy {
+ non_const_copy(non_const_copy&) = default; // expected-note {{not viable}}
+ non_const_copy& operator = (non_const_copy&) & = default; // expected-note {{not viable}}
+ non_const_copy& operator = (non_const_copy&) && = default; // expected-note {{not viable}}
+ non_const_copy() = default; // expected-note {{not viable}}
+};
+
+void fn1 () {
+ non_copiable nc;
+ non_copiable nc2 = nc; // expected-error {{deleted constructor}}
+ nc = nc; // expected-error {{deleted operator}}
+
+ non_const_copy ncc;
+ non_const_copy ncc2 = ncc;
+ ncc = ncc2;
+ const non_const_copy cncc;
+ non_const_copy ncc3 = cncc; // expected-error {{no matching}}
+ ncc = cncc; // expected-error {{no viable overloaded}}
+};
+
+struct non_const_derived : non_const_copy {
+ non_const_derived(const non_const_derived&) = default; // expected-error {{requires it to be non-const}}
+ non_const_derived& operator =(non_const_derived&) = default;
+};
+
+struct bad_decls {
+ bad_decls(volatile bad_decls&) = default; // expected-error {{may not be volatile}}
+ bad_decls&& operator = (bad_decls) = default; // expected-error 2{{lvalue reference}}
+ bad_decls& operator = (volatile bad_decls&) = default; // expected-error {{may not be volatile}}
+ bad_decls& operator = (const bad_decls&) const = default; // expected-error {{may not have 'const' or 'volatile' qualifiers}}
+};
+
+struct A {}; struct B {};
+
+struct except_spec_a {
+ virtual ~except_spec_a() throw(A);
+ except_spec_a() throw(A);
+};
+struct except_spec_b {
+ virtual ~except_spec_b() throw(B);
+ except_spec_b() throw(B);
+};
+
+struct except_spec_d_good : except_spec_a, except_spec_b {
+ ~except_spec_d_good();
+};
+except_spec_d_good::~except_spec_d_good() = default;
+// FIXME: This should error in the virtual override check.
+// It doesn't because we generate the implicit specification later than
+// appropriate.
+struct except_spec_d_bad : except_spec_a, except_spec_b {
+ ~except_spec_d_bad() = default;
+};
+
+// FIXME: This should error because the exceptions spec doesn't match.
+struct except_spec_d_mismatch : except_spec_a, except_spec_b {
+ except_spec_d_mismatch() throw(A) = default;
+};
+struct except_spec_d_match : except_spec_a, except_spec_b {
+ except_spec_d_match() throw(A, B) = default;
+};
diff --git a/test/SemaCXX/cxx0x-defaulted-functions.cpp b/test/SemaCXX/cxx0x-defaulted-functions.cpp
new file mode 100644
index 0000000..86c5fd1
--- /dev/null
+++ b/test/SemaCXX/cxx0x-defaulted-functions.cpp
@@ -0,0 +1,45 @@
+// RUN: %clang_cc1 -std=c++0x -fsyntax-only -verify %s
+
+void fn() = default; // expected-error {{only special member}}
+struct foo {
+ void fn() = default; // expected-error {{only special member}}
+
+ foo() = default;
+ foo(const foo&) = default;
+ foo(foo&) = default;
+ foo& operator = (const foo&) = default;
+ foo& operator = (foo&) = default;
+ ~foo() = default;
+};
+
+struct bar {
+ bar();
+ bar(const bar&);
+ bar(bar&);
+ bar& operator = (const bar&);
+ bar& operator = (bar&);
+ ~bar();
+};
+
+bar::bar() = default;
+bar::bar(const bar&) = default;
+bar::bar(bar&) = default;
+bar& bar::operator = (const bar&) = default;
+bar& bar::operator = (bar&) = default;
+bar::~bar() = default;
+
+// FIXME: static_assert(__is_trivial(foo), "foo should be trivial");
+
+static_assert(!__has_trivial_destructor(bar), "bar's destructor isn't trivial");
+static_assert(!__has_trivial_constructor(bar),
+ "bar's default constructor isn't trivial");
+static_assert(!__has_trivial_copy(bar), "bar has no trivial copy");
+static_assert(!__has_trivial_assign(bar), "bar has no trivial assign");
+
+void tester() {
+ foo f, g(f);
+ bar b, c(b);
+ f = g;
+ b = c;
+}
+
diff --git a/test/SemaCXX/cxx0x-delegating-ctors.cpp b/test/SemaCXX/cxx0x-delegating-ctors.cpp
index b211cb1..a3e6ff3 100644
--- a/test/SemaCXX/cxx0x-delegating-ctors.cpp
+++ b/test/SemaCXX/cxx0x-delegating-ctors.cpp
@@ -7,8 +7,9 @@ struct foo {
foo(int, int);
foo(bool);
foo(char);
- foo(float*);
- foo(float&);
+ foo(const float*);
+ foo(const float&);
+ foo(void*);
};
// Good
@@ -21,16 +22,27 @@ foo::foo () : foo(-1) {
foo::foo (int, int) : foo() {
}
-foo::foo (bool) : foo(true) { // expected-error{{delegates to itself}}
+foo::foo (bool) : foo(true) { // expected-error{{creates a delegation cycle}}
}
// Good
-foo::foo (float* f) : foo(*f) {
+foo::foo (const float* f) : foo(*f) { // expected-note{{it delegates to}}
}
-// FIXME: This should error
-foo::foo (float &f) : foo(&f) {
+foo::foo (const float &f) : foo(&f) { //expected-error{{creates a delegation cycle}} \
+ //expected-note{{which delegates to}}
}
foo::foo (char) : i(3), foo(3) { // expected-error{{must appear alone}}
}
+
+// This should not cause an infinite loop
+foo::foo (void*) : foo(4.0f) {
+}
+
+struct deleted_dtor {
+ ~deleted_dtor() = delete; // expected-note{{function has been explicitly marked deleted here}}
+ deleted_dtor();
+ deleted_dtor(int) : deleted_dtor() // expected-error{{attempt to use a deleted function}}
+ {}
+};
diff --git a/test/SemaCXX/cxx0x-deleted-default-ctor.cpp b/test/SemaCXX/cxx0x-deleted-default-ctor.cpp
new file mode 100644
index 0000000..dcb6ba2
--- /dev/null
+++ b/test/SemaCXX/cxx0x-deleted-default-ctor.cpp
@@ -0,0 +1,120 @@
+// RUN: %clang_cc1 -std=c++0x -fsyntax-only -verify %s
+
+struct non_trivial {
+ non_trivial();
+ non_trivial(const non_trivial&);
+ non_trivial& operator = (const non_trivial&);
+ ~non_trivial();
+};
+
+union bad_union { // expected-note {{marked deleted here}}
+ non_trivial nt;
+};
+bad_union u; // expected-error {{call to deleted constructor}}
+union bad_union2 { // expected-note {{marked deleted here}}
+ const int i;
+};
+bad_union2 u2; // expected-error {{call to deleted constructor}}
+
+struct bad_anon { // expected-note {{marked deleted here}}
+ union {
+ non_trivial nt;
+ };
+};
+bad_anon a; // expected-error {{call to deleted constructor}}
+struct bad_anon2 { // expected-note {{marked deleted here}}
+ union {
+ const int i;
+ };
+};
+bad_anon2 a2; // expected-error {{call to deleted constructor}}
+
+// This would be great except that we implement
+union good_union {
+ const int i;
+ float f;
+};
+good_union gu;
+struct good_anon {
+ union {
+ const int i;
+ float f;
+ };
+};
+good_anon ga;
+
+struct good : non_trivial {
+ non_trivial nt;
+};
+good g;
+
+struct bad_const { // expected-note {{marked deleted here}}
+ const good g;
+};
+bad_const bc; // expected-error {{call to deleted constructor}}
+
+struct good_const {
+ const non_trivial nt;
+};
+good_const gc;
+
+struct no_default {
+ no_default() = delete;
+};
+struct no_dtor {
+ ~no_dtor() = delete;
+};
+
+struct bad_field_default { // expected-note {{marked deleted here}}
+ no_default nd;
+};
+bad_field_default bfd; // expected-error {{call to deleted constructor}}
+struct bad_base_default : no_default { // expected-note {{marked deleted here}}
+};
+bad_base_default bbd; // expected-error {{call to deleted constructor}}
+
+struct bad_field_dtor { // expected-note {{marked deleted here}}
+ no_dtor nd;
+};
+bad_field_dtor bfx; // expected-error {{call to deleted constructor}}
+struct bad_base_dtor : no_dtor { // expected-note {{marked deleted here}}
+};
+bad_base_dtor bbx; // expected-error {{call to deleted constructor}}
+
+struct ambiguous_default {
+ ambiguous_default();
+ ambiguous_default(int = 2);
+};
+struct has_amb_field { // expected-note {{marked deleted here}}
+ ambiguous_default ad;
+};
+has_amb_field haf; // expected-error {{call to deleted constructor}}
+
+class inaccessible_default {
+ inaccessible_default();
+};
+struct has_inacc_field { // expected-note {{marked deleted here}}
+ inaccessible_default id;
+};
+has_inacc_field hif; // expected-error {{call to deleted constructor}}
+
+class friend_default {
+ friend struct has_friend;
+ friend_default();
+};
+struct has_friend {
+ friend_default fd;
+};
+has_friend hf;
+
+struct defaulted_delete {
+ no_default nd;
+ defaulted_delete() = default; // expected-note {{marked deleted here}}
+};
+defaulted_delete dd; // expected-error {{call to deleted constructor}}
+
+struct late_delete {
+ no_default nd;
+ late_delete();
+};
+late_delete::late_delete() = default; // expected-error {{would delete it}}
diff --git a/test/SemaCXX/cxx0x-nontrivial-union.cpp b/test/SemaCXX/cxx0x-nontrivial-union.cpp
new file mode 100644
index 0000000..666e64b
--- /dev/null
+++ b/test/SemaCXX/cxx0x-nontrivial-union.cpp
@@ -0,0 +1,22 @@
+// RUN: %clang_cc1 -std=c++0x -fsyntax-only -verify %s
+
+struct non_trivial {
+ non_trivial();
+ non_trivial(const non_trivial&);
+ non_trivial& operator = (const non_trivial&);
+ ~non_trivial();
+};
+
+union u {
+ non_trivial nt;
+};
+
+union bad {
+ static int i; // expected-error {{static data member}}
+};
+
+struct s {
+ union {
+ non_trivial nt;
+ };
+};
diff --git a/test/SemaCXX/default-arg-special-member.cpp b/test/SemaCXX/default-arg-special-member.cpp
new file mode 100644
index 0000000..8402d382
--- /dev/null
+++ b/test/SemaCXX/default-arg-special-member.cpp
@@ -0,0 +1,12 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s
+// RUN: %clang_cc1 -Wno-default-arg-special-member -Werror -fsyntax-only %s
+
+class foo {
+ foo(foo&, int); // expected-note {{was not a special member function}}
+ foo(int); // expected-note {{was not a special member function}}
+ foo(const foo&); // expected-note {{was a copy constructor}}
+};
+
+foo::foo(foo&, int = 0) { } // expected-warning {{makes this constructor a copy constructor}}
+foo::foo(int = 0) { } // expected-warning {{makes this constructor a default constructor}}
+foo::foo(const foo& = 0) { } //expected-warning {{makes this constructor a default constructor}}
diff --git a/test/SemaCXX/default-constructor-initializers.cpp b/test/SemaCXX/default-constructor-initializers.cpp
index 9da8556..e783f49 100644
--- a/test/SemaCXX/default-constructor-initializers.cpp
+++ b/test/SemaCXX/default-constructor-initializers.cpp
@@ -59,3 +59,10 @@ namespace PR7948 {
struct S { const int x; ~S(); };
const S arr[2] = { { 42 } };
}
+
+// This is valid
+union U {
+ const int i;
+ float f;
+};
+U u;
diff --git a/test/SemaCXX/defaulted-ctor-loop.cpp b/test/SemaCXX/defaulted-ctor-loop.cpp
new file mode 100644
index 0000000..6a41972
--- /dev/null
+++ b/test/SemaCXX/defaulted-ctor-loop.cpp
@@ -0,0 +1,14 @@
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++0x %s
+
+// WARNING: This test may recurse infinitely if failing.
+
+struct foo;
+struct bar {
+ bar(foo&);
+};
+struct foo {
+ bar b;
+ foo()
+ : b(b) // expected-warning{{field is uninitialized}}
+ {}
+};
diff --git a/test/SemaCXX/deleted-function-extension.cpp b/test/SemaCXX/deleted-function-extension.cpp
deleted file mode 100644
index fdf5ac8..0000000
--- a/test/SemaCXX/deleted-function-extension.cpp
+++ /dev/null
@@ -1,8 +0,0 @@
-// RUN: %clang_cc1 -fsyntax-only -verify -std=c++98 %s
-
-struct A {
- A(const A&) = delete; // expected-warning {{deleted function definition accepted as a C++0x extension}}
- A& operator=(const A&) = delete; // expected-warning {{deleted function definition accepted as a C++0x extension}}
-};
-
-void f() = delete; // expected-warning {{deleted function definition accepted as a C++0x extension}}
diff --git a/test/SemaCXX/deleted-function.cpp b/test/SemaCXX/deleted-function.cpp
index b3e1296..6a8965c 100644
--- a/test/SemaCXX/deleted-function.cpp
+++ b/test/SemaCXX/deleted-function.cpp
@@ -7,9 +7,8 @@ void fn() = delete; // expected-note {{candidate function has been explicitly de
void fn2(); // expected-note {{previous declaration is here}}
void fn2() = delete; // expected-error {{deleted definition must be first declaration}}
-void fn3() = delete;
-void fn3() {
- // FIXME: This definition should be invalid.
+void fn3() = delete; // expected-note {{previous definition is here}}
+void fn3() { // expected-error {{redefinition}}
}
void ov(int) {} // expected-note {{candidate function}}
diff --git a/test/SemaCXX/dependent-noexcept-unevaluated.cpp b/test/SemaCXX/dependent-noexcept-unevaluated.cpp
new file mode 100644
index 0000000..5bf6f9e
--- /dev/null
+++ b/test/SemaCXX/dependent-noexcept-unevaluated.cpp
@@ -0,0 +1,41 @@
+// RUN: %clang_cc1 -fsyntax-only -std=c++0x %s
+
+template <class T>
+T&&
+declval() noexcept;
+
+template <class T>
+struct some_trait
+{
+ static const bool value = false;
+};
+
+template <class T>
+void swap(T& x, T& y) noexcept(some_trait<T>::value)
+{
+ T tmp(static_cast<T&&>(x));
+ x = static_cast<T&&>(y);
+ y = static_cast<T&&>(tmp);
+}
+
+template <class T, unsigned N>
+struct array
+{
+ T data[N];
+
+ void swap(array& a) noexcept(noexcept(swap(declval<T&>(), declval<T&>())));
+};
+
+struct DefaultOnly
+{
+ DefaultOnly() = default;
+ DefaultOnly(const DefaultOnly&) = delete;
+ DefaultOnly& operator=(const DefaultOnly&) = delete;
+ ~DefaultOnly() = default;
+};
+
+int main()
+{
+ array<DefaultOnly, 1> a, b;
+}
+
diff --git a/test/SemaCXX/dependent-types.cpp b/test/SemaCXX/dependent-types.cpp
index d9b5323..053e79b 100644
--- a/test/SemaCXX/dependent-types.cpp
+++ b/test/SemaCXX/dependent-types.cpp
@@ -1,4 +1,6 @@
-// RUN: %clang_cc1 -fsyntax-only -pedantic -verify %s
+// RUN: %clang_cc1 -fsyntax-only -pedantic -verify -std=c++0x %s
+
+template<typename T> using U = int &;
template<typename T, int Size> void f() {
T x1;
@@ -7,4 +9,5 @@ template<typename T, int Size> void f() {
T x4[]; // expected-error{{needs an explicit size or an initializer}}
T x5[Size];
int x6[Size];
+ U<T> x7; // expected-error{{declaration of reference variable 'x7' requires an initializer}}
}
diff --git a/test/SemaCXX/destructor.cpp b/test/SemaCXX/destructor.cpp
index 01f21de..ec0539b 100644
--- a/test/SemaCXX/destructor.cpp
+++ b/test/SemaCXX/destructor.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -Wnon-virtual-dtor -verify %s
+// RUN: %clang_cc1 -std=c++0x -fsyntax-only -Wnon-virtual-dtor -Wdelete-non-virtual-dtor -verify %s
class A {
public:
~A();
@@ -173,6 +173,179 @@ template<class T> class TS2 { // expected-warning {{'nonvirtualdtor::TS2<int>' h
TS2<int> foo; // expected-note {{instantiation}}
}
+namespace dnvd { // delete-non-virtual-dtor warning
+struct NP {};
+
+struct B { // expected-warning {{has virtual functions but non-virtual destructor}}
+ virtual void foo();
+};
+
+struct D: B {}; // expected-warning {{has virtual functions but non-virtual destructor}}
+
+struct F final: B {}; // expected-warning {{has virtual functions but non-virtual destructor}}
+
+struct VB {
+ virtual void foo();
+ virtual ~VB();
+};
+
+struct VD: VB {};
+
+struct VF final: VB {};
+
+template <typename T>
+class simple_ptr {
+public:
+ simple_ptr(T* t): _ptr(t) {}
+ ~simple_ptr() { delete _ptr; } // \
+ // expected-warning {{delete called on 'dnvd::B' that has virtual functions but non-virtual destructor}} \
+ // expected-warning {{delete called on 'dnvd::D' that has virtual functions but non-virtual destructor}}
+ T& operator*() const { return *_ptr; }
+private:
+ T* _ptr;
+};
+
+template <typename T>
+class simple_ptr2 {
+public:
+ simple_ptr2(T* t): _ptr(t) {}
+ ~simple_ptr2() { delete _ptr; } // expected-warning {{delete called on 'dnvd::B' that has virtual functions but non-virtual destructor}}
+ T& operator*() const { return *_ptr; }
+private:
+ T* _ptr;
+};
+
+void use(B&);
+void use(VB&);
+
+void nowarnstack() {
+ B b; use(b);
+ D d; use(d);
+ F f; use(f);
+ VB vb; use(vb);
+ VD vd; use(vd);
+ VF vf; use(vf);
+}
+
+void nowarnnonpoly() {
+ {
+ NP* np = new NP();
+ delete np;
+ }
+ {
+ NP* np = new NP[4];
+ delete[] np;
+ }
+}
+
+void nowarnarray() {
+ {
+ B* b = new B[4];
+ delete[] b;
+ }
+ {
+ D* d = new D[4];
+ delete[] d;
+ }
+ {
+ VB* vb = new VB[4];
+ delete[] vb;
+ }
+ {
+ VD* vd = new VD[4];
+ delete[] vd;
+ }
+}
+
+template <typename T>
+void nowarntemplate() {
+ {
+ T* t = new T();
+ delete t;
+ }
+ {
+ T* t = new T[4];
+ delete[] t;
+ }
+}
+
+void nowarn0() {
+ {
+ F* f = new F();
+ delete f;
+ }
+ {
+ VB* vb = new VB();
+ delete vb;
+ }
+ {
+ VB* vb = new VD();
+ delete vb;
+ }
+ {
+ VD* vd = new VD();
+ delete vd;
+ }
+ {
+ VF* vf = new VF();
+ delete vf;
+ }
+}
+
+void warn0() {
+ {
+ B* b = new B();
+ delete b; // expected-warning {{delete called on 'dnvd::B' that has virtual functions but non-virtual destructor}}
+ }
+ {
+ B* b = new D();
+ delete b; // expected-warning {{delete called on 'dnvd::B' that has virtual functions but non-virtual destructor}}
+ }
+ {
+ D* d = new D();
+ delete d; // expected-warning {{delete called on 'dnvd::D' that has virtual functions but non-virtual destructor}}
+ }
+}
+
+void nowarn1() {
+ {
+ simple_ptr<F> f(new F());
+ use(*f);
+ }
+ {
+ simple_ptr<VB> vb(new VB());
+ use(*vb);
+ }
+ {
+ simple_ptr<VB> vb(new VD());
+ use(*vb);
+ }
+ {
+ simple_ptr<VD> vd(new VD());
+ use(*vd);
+ }
+ {
+ simple_ptr<VF> vf(new VF());
+ use(*vf);
+ }
+}
+
+void warn1() {
+ {
+ simple_ptr<B> b(new B()); // expected-note {{in instantiation of member function 'dnvd::simple_ptr<dnvd::B>::~simple_ptr' requested here}}
+ use(*b);
+ }
+ {
+ simple_ptr2<B> b(new D()); // expected-note {{in instantiation of member function 'dnvd::simple_ptr2<dnvd::B>::~simple_ptr2' requested here}}
+ use(*b);
+ }
+ {
+ simple_ptr<D> d(new D()); // expected-note {{in instantiation of member function 'dnvd::simple_ptr<dnvd::D>::~simple_ptr' requested here}}
+ use(*d);
+ }
+}
+}
+
namespace PR9238 {
class B { public: ~B(); };
class C : virtual B { public: ~C() { } };
diff --git a/test/SemaCXX/enum-scoped.cpp b/test/SemaCXX/enum-scoped.cpp
index 8c4bfe7..fc871cf 100644
--- a/test/SemaCXX/enum-scoped.cpp
+++ b/test/SemaCXX/enum-scoped.cpp
@@ -109,3 +109,13 @@ void PR9333() {
scoped_enum e = scoped_enum::yes;
if (e == scoped_enum::no) { }
}
+
+// <rdar://problem/9366066>
+namespace rdar9366066 {
+ enum class X : unsigned { value };
+
+ void f(X x) {
+ x % X::value; // expected-error{{invalid operands to binary expression ('rdar9366066::X' and 'rdar9366066::X')}}
+ x % 8; // expected-error{{invalid operands to binary expression ('rdar9366066::X' and 'int')}}
+ }
+}
diff --git a/test/SemaCXX/expressions.cpp b/test/SemaCXX/expressions.cpp
index c4e9dcc..95ece48 100644
--- a/test/SemaCXX/expressions.cpp
+++ b/test/SemaCXX/expressions.cpp
@@ -32,3 +32,34 @@ namespace test1 {
bar(x += E_zero); // expected-error {{incompatible type}}
}
}
+
+int test2(int x) {
+ return x && 4; // expected-warning {{use of logical && with constant operand; switch to bitwise & or remove constant}}
+
+ return x && sizeof(int) == 4; // no warning, RHS is logical op.
+ return x && true;
+ return x && false;
+ return x || true;
+ return x || false;
+
+ return x && (unsigned)0; // expected-warning {{use of logical && with constant operand; switch to bitwise & or remove constant}}
+
+ return x || (unsigned)1; // expected-warning {{use of logical || with constant operand; switch to bitwise | or remove constant}}
+
+ return x || 0; // expected-warning {{use of logical || with constant operand; switch to bitwise | or remove constant}}
+ return x || 1; // expected-warning {{use of logical || with constant operand; switch to bitwise | or remove constant}}
+ return x || -1; // expected-warning {{use of logical || with constant operand; switch to bitwise | or remove constant}}
+ return x || 5; // expected-warning {{use of logical || with constant operand; switch to bitwise | or remove constant}}
+ return x && 0; // expected-warning {{use of logical && with constant operand; switch to bitwise & or remove constant}}
+ return x && 1; // expected-warning {{use of logical && with constant operand; switch to bitwise & or remove constant}}
+ return x && -1; // expected-warning {{use of logical && with constant operand; switch to bitwise & or remove constant}}
+ return x && 5; // expected-warning {{use of logical && with constant operand; switch to bitwise & or remove constant}}
+ return x || (0); // expected-warning {{use of logical || with constant operand; switch to bitwise | or remove constant}}
+ return x || (1); // expected-warning {{use of logical || with constant operand; switch to bitwise | or remove constant}}
+ return x || (-1); // expected-warning {{use of logical || with constant operand; switch to bitwise | or remove constant}}
+ return x || (5); // expected-warning {{use of logical || with constant operand; switch to bitwise | or remove constant}}
+ return x && (0); // expected-warning {{use of logical && with constant operand; switch to bitwise & or remove constant}}
+ return x && (1); // expected-warning {{use of logical && with constant operand; switch to bitwise & or remove constant}}
+ return x && (-1); // expected-warning {{use of logical && with constant operand; switch to bitwise & or remove constant}}
+ return x && (5); // expected-warning {{use of logical && with constant operand; switch to bitwise & or remove constant}}
+}
diff --git a/test/SemaCXX/generalized-initializers.cpp b/test/SemaCXX/generalized-initializers.cpp
new file mode 100644
index 0000000..ec37a0c
--- /dev/null
+++ b/test/SemaCXX/generalized-initializers.cpp
@@ -0,0 +1,174 @@
+// RUN: %clang_cc1 -std=c++0x -fsyntax-only -verify %s
+// XFAIL: *
+
+template <typename T, typename U>
+struct same_type { static const bool value = false; };
+template <typename T>
+struct same_type<T, T> { static const bool value = true; };
+
+namespace std {
+ typedef decltype(sizeof(int)) size_t;
+
+ // libc++'s implementation
+ template <class _E>
+ class initializer_list
+ {
+ const _E* __begin_;
+ size_t __size_;
+
+ initializer_list(const _E* __b, size_t __s)
+ : __begin_(__b),
+ __size_(__s)
+ {}
+
+ public:
+ typedef _E value_type;
+ typedef const _E& reference;
+ typedef const _E& const_reference;
+ typedef size_t size_type;
+
+ typedef const _E* iterator;
+ typedef const _E* const_iterator;
+
+ initializer_list() : __begin_(nullptr), __size_(0) {}
+
+ size_t size() const {return __size_;}
+ const _E* begin() const {return __begin_;}
+ const _E* end() const {return __begin_ + __size_;}
+ };
+}
+
+namespace integral {
+
+ void initialization() {
+ { const int a{}; static_assert(a == 0, ""); }
+ { const int a = {}; static_assert(a == 0, ""); }
+ { const int a{1}; static_assert(a == 1, ""); }
+ { const int a = {1}; static_assert(a == 1, ""); }
+ { const int a{1, 2}; } // expected-error {{excess elements}}
+ { const int a = {1, 2}; } // expected-error {{excess elements}}
+ { const short a{100000}; } // expected-error {{narrowing conversion}}
+ { const short a = {100000}; } // expected-error {{narrowing conversion}}
+ }
+
+ int function_call() {
+ void takes_int(int);
+ takes_int({1});
+
+ int ar[10];
+ (void) ar[{1}]; // expected-error {{initializer list is illegal with the built-in index operator}}
+
+ return {1};
+ }
+
+ void inline_init() {
+ (void) int{1};
+ (void) new int{1};
+ }
+
+ void initializer_list() {
+ std::initializer_list<int> il = { 1, 2, 3 };
+ std::initializer_list<double> dl = { 1.0, 2.0, 3 };
+ auto l = {1, 2, 3, 4};
+ static_assert(same_type<decltype(l), std::initializer_list<int>>::value, "");
+ auto bl = {1, 2.0}; // expected-error {{cannot deduce}}
+
+ for (int i : {1, 2, 3, 4}) {}
+ }
+
+ struct A {
+ int i;
+ A() : i{1} {}
+ };
+
+}
+
+namespace objects {
+
+ template <int N>
+ struct A {
+ A() { static_assert(N == 0, ""); }
+ A(int, double) { static_assert(N == 1, ""); }
+ A(int, int) { static_assert(N == 2, ""); }
+ A(std::initializer_list<int>) { static_assert(N == 3, ""); }
+ };
+
+ void initialization() {
+ { A<0> a{}; }
+ { A<0> a = {}; }
+ { A<1> a{1, 1.0}; }
+ { A<1> a = {1, 1.0}; }
+ { A<3> a{1, 2, 3, 4, 5, 6, 7, 8}; }
+ { A<3> a = {1, 2, 3, 4, 5, 6, 7, 8}; }
+ { A<3> a{1, 2, 3, 4, 5, 6, 7, 8}; }
+ { A<3> a{1, 2}; }
+ }
+
+ struct C {
+ C();
+ C(int, double);
+ C(int, int);
+ C(std::initializer_list<int>);
+
+ int operator[](C);
+ };
+
+ C function_call() {
+ void takes_C(C);
+ takes_C({1, 1.0});
+
+ C c;
+ c[{1, 1.0}];
+
+ return {1, 1.0};
+ }
+
+ void inline_init() {
+ (void) A<1>{1, 1.0};
+ (void) new A<1>{1, 1.0};
+ }
+
+ struct B {
+ B(C, int, C);
+ };
+
+ void nested_init() {
+ B b{{1, 1.0}, 2, {3, 4, 5, 6, 7}};
+ }
+}
+
+namespace litb {
+
+ // invalid
+ struct A { int a[2]; A():a({1, 2}) { } }; // expected-error {{}}
+
+ // invalid
+ int a({0}); // expected-error {{}}
+
+ // invalid
+ int const &b({0}); // expected-error {{}}
+
+ struct C { explicit C(int, int); C(int, long); };
+
+ // invalid
+ C c({1, 2}); // expected-error {{}}
+
+ // valid (by copy constructor).
+ C d({1, 2L}); // expected-error {{}}
+
+ // valid
+ C e{1, 2};
+
+ struct B {
+ template<typename ...T>
+ B(std::initializer_list<int>, T ...);
+ };
+
+ // invalid (the first phase only considers init-list ctors)
+ // (for the second phase, no constructor is viable)
+ B f{1, 2, 3};
+
+ // valid (T deduced to <>).
+ B g({1, 2, 3});
+
+}
diff --git a/test/SemaCXX/implicit-exception-spec.cpp b/test/SemaCXX/implicit-exception-spec.cpp
new file mode 100644
index 0000000..81babc0
--- /dev/null
+++ b/test/SemaCXX/implicit-exception-spec.cpp
@@ -0,0 +1,63 @@
+// RUN: %clang_cc1 -fsyntax-only -fcxx-exceptions -verify -std=c++0x -Wall %s
+
+template<bool b> struct ExceptionIf { static int f(); };
+template<> struct ExceptionIf<false> { typedef int f; };
+
+// The exception specification of a defaulted default constructor depends on
+// the contents of in-class member initializers. However, the in-class member
+// initializers can depend on the exception specification of the constructor,
+// since the class is considered complete within them. We reject any such cases.
+namespace InClassInitializers {
+ // Noexcept::Noexcept() is implicitly declared as noexcept(false), because it
+ // directly invokes ThrowSomething(). However...
+ //
+ // If noexcept(Noexcept()) is false, then Noexcept() is a constant expression,
+ // so noexcept(Noexcept()) is true. But if noexcept(Noexcept()) is true, then
+ // Noexcept::Noexcept is not declared constexpr, therefore noexcept(Noexcept())
+ // is false.
+ bool ThrowSomething() noexcept(false);
+ struct ConstExpr {
+ bool b = noexcept(ConstExpr()) && ThrowSomething(); // expected-error {{exception specification is not available until end of class definition}}
+ };
+ // We can use it now.
+ bool w = noexcept(ConstExpr());
+
+ // Much more obviously broken: we can't parse the initializer without already
+ // knowing whether it produces a noexcept expression.
+ struct TemplateArg {
+ int n = ExceptionIf<noexcept(TemplateArg())>::f(); // expected-error {{exception specification is not available until end of class definition}}
+ };
+ bool x = noexcept(TemplateArg());
+
+ // And within a nested class.
+ struct Nested {
+ struct Inner {
+ int n = ExceptionIf<noexcept(Nested())>::f(); // expected-error {{exception specification is not available until end of class definition}}
+ } inner;
+ };
+ bool y = noexcept(Nested());
+ bool z = noexcept(Nested::Inner());
+}
+
+// FIXME:
+// The same problem arises in delayed parsing of exception specifications,
+// which clang does not yet support.
+namespace ExceptionSpecification {
+ struct Nested { // expected-note {{not complete}}
+ struct T {
+ T() noexcept(!noexcept(Nested())); // expected-error {{incomplete type}}
+ } t;
+ };
+}
+
+// FIXME:
+// The same problem arises in delayed parsing of default arguments,
+// which clang does not yet support.
+namespace DefaultArgument {
+ // FIXME: this diagnostic is completely wrong.
+ struct Default { // expected-note {{explicitly marked deleted here}}
+ struct T {
+ T(int = ExceptionIf<noexcept(Default())::f()); // expected-error {{call to deleted constructor}}
+ } t;
+ };
+}
diff --git a/test/SemaCXX/implicit-member-functions.cpp b/test/SemaCXX/implicit-member-functions.cpp
index 5333094..8451739 100644
--- a/test/SemaCXX/implicit-member-functions.cpp
+++ b/test/SemaCXX/implicit-member-functions.cpp
@@ -1,7 +1,7 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s
struct A { };
-A::A() { } // expected-error {{definition of implicitly declared constructor}}
+A::A() { } // expected-error {{definition of implicitly declared default constructor}}
struct B { };
B::B(const B&) { } // expected-error {{definition of implicitly declared copy constructor}}
diff --git a/test/SemaCXX/member-expr.cpp b/test/SemaCXX/member-expr.cpp
index 68af415..981bae7 100644
--- a/test/SemaCXX/member-expr.cpp
+++ b/test/SemaCXX/member-expr.cpp
@@ -124,10 +124,10 @@ namespace PR9025 {
return fun.x; // expected-error{{base of member reference is an overloaded function; perhaps you meant to call it with no arguments?}}
}
- S fun2(); // expected-note{{possibly valid overload here}}
- S fun2(int i); // expected-note{{possibly valid overload here}}
+ S fun2();
+ S fun2(int i);
int g2() {
- return fun2.x; // expected-error{{base of member reference is an overloaded function; perhaps you meant to call it?}}
+ return fun2.x; // expected-error{{base of member reference is an overloaded function; perhaps you meant to call it with no arguments?}}
}
S fun3(int i=0);
@@ -140,4 +140,10 @@ namespace PR9025 {
int g4() {
return fun4.x; // expected-error{{base of member reference is a function; perhaps you meant to call it?}}
}
+
+ S fun5(int i); // expected-note{{possibly valid overload here}}
+ S fun5(float f); // expected-note{{possibly valid overload here}}
+ int g5() {
+ return fun5.x; // expected-error{{base of member reference is an overloaded function; perhaps you meant to call it?}}
+ }
}
diff --git a/test/SemaCXX/member-init.cpp b/test/SemaCXX/member-init.cpp
new file mode 100644
index 0000000..1b8c523
--- /dev/null
+++ b/test/SemaCXX/member-init.cpp
@@ -0,0 +1,50 @@
+// RUN: %clang_cc1 -fsyntax-only -fcxx-exceptions -verify -std=c++0x -Wall %s
+
+struct Bitfield {
+ int n : 3 = 7; // expected-error {{bitfield member cannot have an in-class initializer}}
+};
+
+int a;
+class NoWarning {
+ int &n = a;
+public:
+ int &GetN() { return n; }
+};
+
+bool b();
+int k;
+struct Recurse {
+ int &n = b() ? Recurse().n : k; // ok
+};
+
+struct UnknownBound {
+ int as[] = { 1, 2, 3 }; // expected-error {{array bound cannot be deduced from an in-class initializer}}
+ int bs[4] = { 4, 5, 6, 7 };
+ int cs[] = { 8, 9, 10 }; // expected-error {{array bound cannot be deduced from an in-class initializer}}
+};
+
+template<int n> struct T { static const int B; };
+template<> struct T<2> { template<int C, int D> using B = int; };
+const int C = 0, D = 0;
+struct S {
+ int as[] = { decltype(x)::B<C, D>(0) }; // expected-error {{array bound cannot be deduced from an in-class initializer}}
+ T<sizeof(as) / sizeof(int)> x; // expected-error {{requires a type specifier}}
+};
+
+struct ThrowCtor { ThrowCtor(int) noexcept(false); };
+struct NoThrowCtor { NoThrowCtor(int) noexcept(true); };
+
+struct Throw { ThrowCtor tc = 42; };
+struct NoThrow { NoThrowCtor tc = 42; };
+
+static_assert(!noexcept(Throw()), "incorrect exception specification");
+static_assert(noexcept(NoThrow()), "incorrect exception specification");
+
+struct CheckExcSpec {
+ CheckExcSpec() noexcept(true) = default;
+ int n = 0;
+};
+struct CheckExcSpecFail {
+ CheckExcSpecFail() noexcept(true) = default; // expected-error {{exception specification of explicitly defaulted default constructor does not match the calculated one}}
+ ThrowCtor tc = 123;
+};
diff --git a/test/SemaCXX/member-pointer.cpp b/test/SemaCXX/member-pointer.cpp
index 31c651a..de3b211 100644
--- a/test/SemaCXX/member-pointer.cpp
+++ b/test/SemaCXX/member-pointer.cpp
@@ -271,3 +271,28 @@ namespace rdar8358512 {
template void B<int>::test0b(); // expected-note {{in instantiation}}
}
+
+namespace PR9973 {
+ template<class R, class T> struct dm
+ {
+ typedef R T::*F;
+ F f_;
+ template<class U> int & call(U u)
+ { return u->*f_; } // expected-error{{non-const lvalue reference to type 'int' cannot bind to a temporary of type '<bound member function type>'}}
+
+ template<class U> int operator()(U u)
+ { call(u); } // expected-note{{in instantiation of}}
+ };
+
+ template<class R, class T>
+ dm<R, T> mem_fn(R T::*) ;
+
+ struct test
+ { int nullary_v(); };
+
+ void f()
+ {
+ test* t;
+ mem_fn(&test::nullary_v)(t); // expected-note{{in instantiation of}}
+ }
+}
diff --git a/test/SemaCXX/nullptr.cpp b/test/SemaCXX/nullptr.cpp
index 84c80aa..d69af58 100644
--- a/test/SemaCXX/nullptr.cpp
+++ b/test/SemaCXX/nullptr.cpp
@@ -60,6 +60,10 @@ nullptr_t f(nullptr_t null)
// You can reinterpret_cast nullptr to an integer.
(void)reinterpret_cast<uintptr_t>(nullptr);
+ (void)reinterpret_cast<uintptr_t>(*pn);
+
+ int *ip = *pn;
+ if (*pn) { }
// You can throw nullptr.
throw nullptr;
@@ -104,3 +108,56 @@ namespace test3 {
f("%p", nullptr);
}
}
+
+int array0[__is_scalar(nullptr_t)? 1 : -1];
+int array1[__is_pod(nullptr_t)? 1 : -1];
+int array2[sizeof(nullptr_t) == sizeof(void*)? 1 : -1];
+
+// FIXME: when we implement constexpr, this will be testable.
+#if 0
+int relational0[nullptr < nullptr? -1 : 1];
+int relational1[nullptr > nullptr? -1 : 1];
+int relational2[nullptr <= nullptr? 1 : -1];
+int relational3[nullptr >= nullptr? 1 : -1];
+int equality[nullptr == nullptr? 1 : -1];
+int inequality[nullptr != nullptr? -1 : 1];
+#endif
+
+namespace overloading {
+ int &f1(int*);
+ float &f1(bool);
+
+ void test_f1() {
+ int &ir = (f1)(nullptr);
+ }
+
+ struct ConvertsToNullPtr {
+ operator nullptr_t() const;
+ };
+
+ void test_conversion(ConvertsToNullPtr ctn) {
+ (void)(ctn == ctn);
+ (void)(ctn != ctn);
+ (void)(ctn <= ctn);
+ (void)(ctn >= ctn);
+ (void)(ctn < ctn);
+ (void)(ctn > ctn);
+ }
+}
+
+namespace templates {
+ template<typename T, nullptr_t Value>
+ struct X {
+ X() { ptr = Value; }
+
+ T *ptr;
+ };
+
+ X<int, nullptr> x;
+
+
+ template<int (*fp)(int), int* p, int A::* pmd, int (A::*pmf)(int)>
+ struct X2 {};
+
+ X2<nullptr, nullptr, nullptr, nullptr> x2;
+}
diff --git a/test/SemaCXX/overload-call.cpp b/test/SemaCXX/overload-call.cpp
index 81a88a3..9cc4899 100644
--- a/test/SemaCXX/overload-call.cpp
+++ b/test/SemaCXX/overload-call.cpp
@@ -503,3 +503,25 @@ namespace rdar8499524 {
g(W());
}
}
+
+namespace rdar9173984 {
+ template <typename T, unsigned long N> int &f(const T (&)[N]);
+ template <typename T> float &f(const T *);
+
+ void test() {
+ int arr[2] = {0, 0};
+ int *arrp = arr;
+ int &ir = f(arr);
+ float &fr = f(arrp);
+ }
+}
+
+namespace PR9507 {
+ void f(int * const&); // expected-note{{candidate function}}
+ void f(int const(&)[1]); // expected-note{{candidate function}}
+
+ int main() {
+ int n[1];
+ f(n); // expected-error{{call to 'f' is ambiguous}}
+ }
+}
diff --git a/test/SemaCXX/overloaded-operator.cpp b/test/SemaCXX/overloaded-operator.cpp
index 44d013f..462d023 100644
--- a/test/SemaCXX/overloaded-operator.cpp
+++ b/test/SemaCXX/overloaded-operator.cpp
@@ -33,7 +33,7 @@ struct A {
A make_A();
-bool operator==(A&, Z&); // expected-note 2{{candidate function}}
+bool operator==(A&, Z&); // expected-note 3{{candidate function}}
void h(A a, const A ac, Z z) {
make_A() == z;
@@ -68,7 +68,7 @@ struct E2 {
};
// C++ [over.match.oper]p3 - enum restriction.
-float& operator==(E1, E2);
+float& operator==(E1, E2); // expected-note{{candidate function}}
void enum_test(Enum1 enum1, Enum2 enum2, E1 e1, E2 e2, Enum1 next_enum1) {
float &f1 = (e1 == e2);
@@ -85,8 +85,8 @@ class pr5244_foo
pr5244_foo(char);
};
-bool operator==(const pr5244_foo& s1, const pr5244_foo& s2);
-bool operator==(char c, const pr5244_foo& s);
+bool operator==(const pr5244_foo& s1, const pr5244_foo& s2); // expected-note{{candidate function}}
+bool operator==(char c, const pr5244_foo& s); // expected-note{{candidate function}}
enum pr5244_bar
{
@@ -399,3 +399,12 @@ namespace rdar9136502 {
y << x.i; // expected-error{{a bound member function may only be called}}
}
}
+
+namespace rdar9222009 {
+class StringRef {
+ inline bool operator==(StringRef LHS, StringRef RHS) { // expected-error{{overloaded 'operator==' must be a binary operator (has 3 parameters)}}
+ return !(LHS == RHS); // expected-error{{invalid operands to binary expression ('rdar9222009::StringRef' and 'rdar9222009::StringRef')}}
+ }
+};
+
+}
diff --git a/test/SemaCXX/redeclared-alias-template.cpp b/test/SemaCXX/redeclared-alias-template.cpp
new file mode 100644
index 0000000..b368fcf
--- /dev/null
+++ b/test/SemaCXX/redeclared-alias-template.cpp
@@ -0,0 +1,23 @@
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++0x %s
+
+template<typename T> using A = int; // expected-note 2{{previous}}
+template<typename T> using A = char; // expected-error {{type alias template redefinition with different types ('char' vs 'int')}}
+template<typename T1, typename T2> using A = T1; // expected-error {{too many template parameters in template redeclaration}}
+
+template<typename T1, typename T2> using B = T1; // expected-note {{previous}}
+template<typename T2, typename T1> using B = T1; // expected-error {{type alias template redefinition with different types}}
+
+
+template<typename> struct S;
+template<template<typename> class F> using FInt = F<int>;
+template<typename X> using SXRInt = FInt<S<X>::template R>;
+template<typename X> using SXRInt = typename S<X>::template R<int>; // ok, redeclaration.
+
+template<template<typename> class> struct TT;
+
+namespace FilterLookup {
+ TT<A> f(); // expected-note {{previous declaration is here}}
+
+ template<typename> using A = int;
+ TT<A> f(); // expected-error {{functions that differ only in their return type cannot be overloaded}}
+}
diff --git a/test/SemaCXX/reinterpret-cast.cpp b/test/SemaCXX/reinterpret-cast.cpp
index f526249..68005a5 100644
--- a/test/SemaCXX/reinterpret-cast.cpp
+++ b/test/SemaCXX/reinterpret-cast.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -verify -ffreestanding %s
+// RUN: %clang_cc1 -fsyntax-only -verify -ffreestanding -Wundefined-reinterpret-cast %s
#include <stdint.h>
@@ -116,3 +116,163 @@ namespace PR9564 {
__attribute((ext_vector_type(4))) typedef float v4;
float& w(v4 &a) { return reinterpret_cast<float&>(a[1]); } // expected-error {{not allowed}}
}
+
+void dereference_reinterpret_cast() {
+ struct A {};
+ typedef A A2;
+ class B {};
+ typedef B B2;
+ A a;
+ B b;
+ A2 a2;
+ B2 b2;
+ long l;
+ double d;
+ float f;
+ char c;
+ unsigned char uc;
+ void* v_ptr;
+ (void)reinterpret_cast<double&>(l); // expected-warning {{reinterpret_cast from 'long' to 'double &' has undefined behavior}}
+ (void)*reinterpret_cast<double*>(&l); // expected-warning {{dereference of type 'double *' that was reinterpret_cast from type 'long *' has undefined behavior}}
+ (void)reinterpret_cast<double&>(f); // expected-warning {{reinterpret_cast from 'float' to 'double &' has undefined behavior}}
+ (void)*reinterpret_cast<double*>(&f); // expected-warning {{dereference of type 'double *' that was reinterpret_cast from type 'float *' has undefined behavior}}
+ (void)reinterpret_cast<float&>(l); // expected-warning {{reinterpret_cast from 'long' to 'float &' has undefined behavior}}
+ (void)*reinterpret_cast<float*>(&l); // expected-warning {{dereference of type 'float *' that was reinterpret_cast from type 'long *' has undefined behavior}}
+ (void)reinterpret_cast<float&>(d); // expected-warning {{reinterpret_cast from 'double' to 'float &' has undefined behavior}}
+ (void)*reinterpret_cast<float*>(&d); // expected-warning {{dereference of type 'float *' that was reinterpret_cast from type 'double *' has undefined behavior}}
+
+ // TODO: add warning for tag types
+ (void)reinterpret_cast<A&>(b);
+ (void)*reinterpret_cast<A*>(&b);
+ (void)reinterpret_cast<B&>(a);
+ (void)*reinterpret_cast<B*>(&a);
+ (void)reinterpret_cast<A2&>(b2);
+ (void)*reinterpret_cast<A2*>(&b2);
+ (void)reinterpret_cast<B2&>(a2);
+ (void)*reinterpret_cast<B2*>(&a2);
+
+ // Casting to itself is allowed
+ (void)reinterpret_cast<A&>(a);
+ (void)*reinterpret_cast<A*>(&a);
+ (void)reinterpret_cast<B&>(b);
+ (void)*reinterpret_cast<B*>(&b);
+ (void)reinterpret_cast<long&>(l);
+ (void)*reinterpret_cast<long*>(&l);
+ (void)reinterpret_cast<double&>(d);
+ (void)*reinterpret_cast<double*>(&d);
+ (void)reinterpret_cast<char&>(c);
+ (void)*reinterpret_cast<char*>(&c);
+
+ // Casting to and from chars are allowable
+ (void)reinterpret_cast<A&>(c);
+ (void)*reinterpret_cast<A*>(&c);
+ (void)reinterpret_cast<B&>(c);
+ (void)*reinterpret_cast<B*>(&c);
+ (void)reinterpret_cast<long&>(c);
+ (void)*reinterpret_cast<long*>(&c);
+ (void)reinterpret_cast<double&>(c);
+ (void)*reinterpret_cast<double*>(&c);
+ (void)reinterpret_cast<char&>(l);
+ (void)*reinterpret_cast<char*>(&l);
+ (void)reinterpret_cast<char&>(d);
+ (void)*reinterpret_cast<char*>(&d);
+ (void)reinterpret_cast<char&>(f);
+ (void)*reinterpret_cast<char*>(&f);
+
+ // Casting from void pointer.
+ (void)*reinterpret_cast<A*>(v_ptr);
+ (void)*reinterpret_cast<B*>(v_ptr);
+ (void)*reinterpret_cast<long*>(v_ptr);
+ (void)*reinterpret_cast<double*>(v_ptr);
+ (void)*reinterpret_cast<float*>(v_ptr);
+
+ // Casting to void pointer
+ (void)*reinterpret_cast<void*>(&a);
+ (void)*reinterpret_cast<void*>(&b);
+ (void)*reinterpret_cast<void*>(&l);
+ (void)*reinterpret_cast<void*>(&d);
+ (void)*reinterpret_cast<void*>(&f);
+}
+
+void reinterpret_cast_whitelist () {
+ // the dynamic type of the object
+ int a;
+ float b;
+ (void)reinterpret_cast<int&>(a);
+ (void)*reinterpret_cast<int*>(&a);
+ (void)reinterpret_cast<float&>(b);
+ (void)*reinterpret_cast<float*>(&b);
+
+ // a cv-qualified version of the dynamic object
+ (void)reinterpret_cast<const int&>(a);
+ (void)*reinterpret_cast<const int*>(&a);
+ (void)reinterpret_cast<volatile int&>(a);
+ (void)*reinterpret_cast<volatile int*>(&a);
+ (void)reinterpret_cast<const volatile int&>(a);
+ (void)*reinterpret_cast<const volatile int*>(&a);
+ (void)reinterpret_cast<const float&>(b);
+ (void)*reinterpret_cast<const float*>(&b);
+ (void)reinterpret_cast<volatile float&>(b);
+ (void)*reinterpret_cast<volatile float*>(&b);
+ (void)reinterpret_cast<const volatile float&>(b);
+ (void)*reinterpret_cast<const volatile float*>(&b);
+
+ // a type that is the signed or unsigned type corresponding to the dynamic
+ // type of the object
+ signed d;
+ unsigned e;
+ (void)reinterpret_cast<signed&>(d);
+ (void)*reinterpret_cast<signed*>(&d);
+ (void)reinterpret_cast<signed&>(e);
+ (void)*reinterpret_cast<signed*>(&e);
+ (void)reinterpret_cast<unsigned&>(d);
+ (void)*reinterpret_cast<unsigned*>(&d);
+ (void)reinterpret_cast<unsigned&>(e);
+ (void)*reinterpret_cast<unsigned*>(&e);
+
+ // a type that is the signed or unsigned type corresponding a cv-qualified
+ // version of the dynamic type the object
+ (void)reinterpret_cast<const signed&>(d);
+ (void)*reinterpret_cast<const signed*>(&d);
+ (void)reinterpret_cast<const signed&>(e);
+ (void)*reinterpret_cast<const signed*>(&e);
+ (void)reinterpret_cast<const unsigned&>(d);
+ (void)*reinterpret_cast<const unsigned*>(&d);
+ (void)reinterpret_cast<const unsigned&>(e);
+ (void)*reinterpret_cast<const unsigned*>(&e);
+ (void)reinterpret_cast<volatile signed&>(d);
+ (void)*reinterpret_cast<volatile signed*>(&d);
+ (void)reinterpret_cast<volatile signed&>(e);
+ (void)*reinterpret_cast<volatile signed*>(&e);
+ (void)reinterpret_cast<volatile unsigned&>(d);
+ (void)*reinterpret_cast<volatile unsigned*>(&d);
+ (void)reinterpret_cast<volatile unsigned&>(e);
+ (void)*reinterpret_cast<volatile unsigned*>(&e);
+ (void)reinterpret_cast<const volatile signed&>(d);
+ (void)*reinterpret_cast<const volatile signed*>(&d);
+ (void)reinterpret_cast<const volatile signed&>(e);
+ (void)*reinterpret_cast<const volatile signed*>(&e);
+ (void)reinterpret_cast<const volatile unsigned&>(d);
+ (void)*reinterpret_cast<const volatile unsigned*>(&d);
+ (void)reinterpret_cast<const volatile unsigned&>(e);
+ (void)*reinterpret_cast<const volatile unsigned*>(&e);
+
+ // an aggregate or union type that includes one of the aforementioned types
+ // among its members (including, recursively, a member of a subaggregate or
+ // contained union)
+ // TODO: checking is not implemented for tag types
+
+ // a type that is a (possible cv-qualified) base class type of the dynamic
+ // type of the object
+ // TODO: checking is not implemented for tag types
+
+ // a char or unsigned char type
+ (void)reinterpret_cast<char&>(a);
+ (void)*reinterpret_cast<char*>(&a);
+ (void)reinterpret_cast<unsigned char&>(a);
+ (void)*reinterpret_cast<unsigned char*>(&a);
+ (void)reinterpret_cast<char&>(b);
+ (void)*reinterpret_cast<char*>(&b);
+ (void)reinterpret_cast<unsigned char&>(b);
+ (void)*reinterpret_cast<unsigned char*>(&b);
+}
diff --git a/test/SemaCXX/return.cpp b/test/SemaCXX/return.cpp
index af7f50c..b457f6a 100644
--- a/test/SemaCXX/return.cpp
+++ b/test/SemaCXX/return.cpp
@@ -39,6 +39,11 @@ g();
char* const h(); // expected-warning{{'const' type qualifier on return type has no effect}}
char* volatile i(); // expected-warning{{'volatile' type qualifier on return type has no effect}}
+char*
+volatile // expected-warning{{'const volatile' type qualifiers on return type have no effect}}
+const
+j();
+
const volatile int scalar_cv(); // expected-warning{{'const volatile' type qualifiers on return type have no effect}}
}
@@ -53,3 +58,14 @@ namespace PR9328 {
class foo {
operator int * const ();
};
+
+namespace PR10057 {
+ struct S {
+ ~S();
+ };
+
+ template <class VarType>
+ void Test(const VarType& value) {
+ return S() = value;
+ }
+}
diff --git a/test/SemaCXX/struct-class-redecl.cpp b/test/SemaCXX/struct-class-redecl.cpp
index d3d6d79..5c59578 100644
--- a/test/SemaCXX/struct-class-redecl.cpp
+++ b/test/SemaCXX/struct-class-redecl.cpp
@@ -1,8 +1,164 @@
// RUN: %clang_cc1 -fsyntax-only -Wmismatched-tags -verify %s
+// RUN: %clang_cc1 -fsyntax-only -Wmismatched-tags %s 2>&1 | FileCheck %s
class X; // expected-note 2{{here}}
typedef struct X * X_t; // expected-warning{{previously declared}}
+union X { int x; float y; }; // expected-error{{use of 'X' with tag type that does not match previous declaration}}
-template<typename T> struct Y; // expected-note{{previous}}
+template<typename T> struct Y; // expected-note{{did you mean class here?}}
template<class U> class Y { }; // expected-warning{{previously declared}}
-union X { int x; float y; }; // expected-error{{use of 'X' with tag type that does not match previous declaration}}
+class A;
+class A; // expected-note{{previous use is here}}
+struct A; // expected-warning{{struct 'A' was previously declared as a class}}
+
+class B; // expected-note{{did you mean struct here?}}
+class B; // expected-note{{previous use is here}}\
+ // expected-note{{did you mean struct here?}}
+struct B; // expected-warning{{struct 'B' was previously declared as a class}}
+struct B {}; // expected-warning{{'B' defined as a struct here but previously declared as a class}}
+
+class C; // expected-note{{previous use is here}}
+struct C; // expected-warning{{struct 'C' was previously declared as a class}}\
+ // expected-note{{previous use is here}}\
+ // expected-note{{did you mean class here?}}
+class C; // expected-warning{{class 'C' was previously declared as a struct}}\
+ // expected-note{{previous use is here}}
+struct C; // expected-warning{{struct 'C' was previously declared as a class}}\
+ // expected-note{{did you mean class here?}}
+class C {}; // expected-warning{{'C' defined as a class here but previously declared as a struct}}
+
+struct D {}; // expected-note{{previous definition is here}}\
+ // expected-note{{previous use is here}}
+class D {}; // expected-error{{redefinition of 'D'}}
+struct D;
+class D; // expected-warning{{class 'D' was previously declared as a struct}}\
+ // expected-note{{did you mean struct here?}}
+
+class E;
+class E;
+class E {};
+class E;
+
+struct F;
+struct F;
+struct F {};
+struct F;
+
+template<class U> class G; // expected-note{{previous use is here}}\
+ // expected-note{{did you mean struct here?}}
+template<class U> struct G; // expected-warning{{struct template 'G' was previously declared as a class template}}
+template<class U> struct G {}; // expected-warning{{'G' defined as a struct template here but previously declared as a class template}}
+
+/*
+*** 'X' messages ***
+CHECK: warning: struct 'X' was previously declared as a class
+CHECK: {{^}}typedef struct X * X_t;
+CHECK: {{^}} ^{{$}}
+CHECK: note: previous use is here
+CHECK: {{^}}class X;
+CHECK: {{^}} ^{{$}}
+CHECK: error: use of 'X' with tag type that does not match previous declaration
+CHECK: {{^}}union X { int x; float y; };
+CHECK: {{^}}^~~~~{{$}}
+CHECK: {{^}}class{{$}}
+CHECK: note: previous use is here
+CHECK: {{^}}class X;
+CHECK: {{^}} ^{{$}}
+*** 'Y' messages ***
+CHECK: warning: 'Y' defined as a class template here but
+ previously declared as a struct template
+CHECK: {{^}}template<class U> class Y { };
+CHECK: {{^}} ^{{$}}
+CHECK: note: did you mean class here?
+CHECK: {{^}}template<typename T> struct Y;
+CHECK: {{^}} ^~~~~~{{$}}
+CHECK: {{^}} class{{$}}
+*** 'A' messages ***
+CHECK: warning: struct 'A' was previously declared as a class
+CHECK: {{^}}struct A;
+CHECK: {{^}}^{{$}}
+CHECK: note: previous use is here
+CHECK: {{^}}class A;
+CHECK: {{^}} ^{{$}}
+*** 'B' messages ***
+CHECK: warning: struct 'B' was previously declared as a class
+CHECK: {{^}}struct B;
+CHECK: {{^}}^{{$}}
+CHECK: note: previous use is here
+CHECK: {{^}}class B;
+CHECK: {{^}} ^{{$}}
+CHECK: 'B' defined as a struct here but previously declared as a class
+CHECK: {{^}}struct B {};
+CHECK: {{^}}^{{$}}
+CHECK: note: did you mean struct here?
+CHECK: {{^}}class B;
+CHECK: {{^}}^~~~~{{$}}
+CHECK: {{^}}struct{{$}}
+CHECK: note: did you mean struct here?
+CHECK: {{^}}class B;
+CHECK: {{^}}^~~~~{{$}}
+CHECK: {{^}}struct{{$}}
+*** 'C' messages ***
+CHECK: warning: struct 'C' was previously declared as a class
+CHECK: {{^}}struct C;
+CHECK: {{^}}^{{$}}
+CHECK: note: previous use is here
+CHECK: {{^}}class C;
+CHECK: {{^}} ^{{$}}
+CHECK: warning: class 'C' was previously declared as a struct
+CHECK: {{^}}class C;
+CHECK: {{^}}^{{$}}
+CHECK: note: previous use is here
+CHECK: {{^}}struct C;
+CHECK: {{^}} ^{{$}}
+CHECK: warning: struct 'C' was previously declared as a class
+CHECK: {{^}}struct C;
+CHECK: {{^}}^{{$}}
+CHECK: note: previous use is here
+CHECK: {{^}}class C;
+CHECK: {{^}} ^{{$}}
+CHECK: warning: 'C' defined as a class here but previously declared as a struct
+CHECK: {{^}}class C {};
+CHECK: {{^}}^{{$}}
+CHECK: note: did you mean class here?
+CHECK: {{^}}struct C;
+CHECK: {{^}}^~~~~~{{$}}
+CHECK: {{^}}class{{$}}
+CHECK: note: did you mean class here?
+CHECK: {{^}}struct C;
+CHECK: {{^}}^~~~~~{{$}}
+CHECK: {{^}}class{{$}}
+*** 'D' messages ***
+CHECK: error: redefinition of 'D'
+CHECK: {{^}}class D {};
+CHECK: {{^}} ^{{$}}
+CHECK: note: previous definition is here
+CHECK: {{^}}struct D {};
+CHECK: {{^}} ^{{$}}
+CHECK: warning: class 'D' was previously declared as a struct
+CHECK: {{^}}class D;
+CHECK: {{^}}^{{$}}
+CHECK: note: previous use is here
+CHECK: {{^}}struct D {};
+CHECK: {{^}} ^{{$}}
+CHECK: note: did you mean struct here?
+CHECK: {{^}}class D;
+CHECK: {{^}}^~~~~{{$}}
+CHECK: {{^}}struct{{$}}
+*** 'E' messages ***
+*** 'F' messages ***
+*** 'G' messages ***
+CHECK: warning: struct template 'G' was previously declared as a class template
+CHECK: {{^}}template<class U> struct G;
+CHECK: {{^}} ^{{$}}
+CHECK: note: previous use is here
+CHECK: {{^}}template<class U> class G;
+CHECK: {{^}} ^{{$}}
+CHECK: warning: 'G' defined as a struct template here but previously declared as a class template
+CHECK: {{^}}template<class U> struct G {};
+CHECK: {{^}} ^{{$}}
+CHECK: note: did you mean struct here?
+CHECK: {{^}}template<class U> class G;
+CHECK: {{^}} ^~~~~
+CHECK: {{^}} struct
+*/
diff --git a/test/SemaCXX/switch.cpp b/test/SemaCXX/switch.cpp
index 3882a1f..8a8cf33 100644
--- a/test/SemaCXX/switch.cpp
+++ b/test/SemaCXX/switch.cpp
@@ -8,7 +8,7 @@ void test() {
}
int n = 3;
- switch (n && 1) { // expected-warning {{bool}}
+ switch (n && true) { // expected-warning {{bool}}
case 1:
break;
}
diff --git a/test/SemaCXX/tag-ambig.cpp b/test/SemaCXX/tag-ambig.cpp
new file mode 100644
index 0000000..6403cf3
--- /dev/null
+++ b/test/SemaCXX/tag-ambig.cpp
@@ -0,0 +1,28 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s
+
+// <rdar://problem/9168556>
+typedef struct Point Point;
+
+namespace NameSpace {
+ class Point;
+}
+
+using namespace NameSpace;
+
+class Test
+{
+public:
+ struct Point { };
+ virtual bool testMethod (Test::Point& p) = 0;
+};
+
+// PR8151
+namespace A { struct Face {}; }
+namespace B { struct Face {}; }
+using namespace A;
+using namespace B;
+
+class C {
+ struct Face;
+ Face *mFaces;
+};
diff --git a/test/SemaCXX/type-traits.cpp b/test/SemaCXX/type-traits.cpp
index 96e9696..30cc6a3 100644
--- a/test/SemaCXX/type-traits.cpp
+++ b/test/SemaCXX/type-traits.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fsyntax-only -verify %s
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fsyntax-only -verify -std=gnu++0x %s
#define T(b) (b) ? 1 : -1
#define F(b) (b) ? -1 : 1
@@ -38,8 +38,7 @@ typedef Derives DerivesArNB[];
struct DerivesEmpty : Empty {};
struct HasCons { HasCons(int); };
struct HasCopyAssign { HasCopyAssign operator =(const HasCopyAssign&); };
-struct HasMoveAssign { HasMoveAssign operator =(const HasMoveAssign&&); }; // \
- // expected-warning {{rvalue references}}
+struct HasMoveAssign { HasMoveAssign operator =(const HasMoveAssign&&); };
struct HasDest { ~HasDest(); };
class HasPriv { int priv; };
class HasProt { protected: int prot; };
@@ -870,6 +869,15 @@ struct NonTrivialStruct {
}
};
+struct SuperNonTrivialStruct {
+ SuperNonTrivialStruct() { }
+ ~SuperNonTrivialStruct() { }
+};
+
+struct NonTCStruct {
+ NonTCStruct(const NonTCStruct&) {}
+};
+
void is_trivial2()
{
int t01[T(__is_trivial(char))];
@@ -897,6 +905,39 @@ void is_trivial2()
int t30[F(__is_trivial(void))];
int t31[F(__is_trivial(NonTrivialStruct))];
+ int t32[F(__is_trivial(SuperNonTrivialStruct))];
+ int t33[F(__is_trivial(NonTCStruct))];
+}
+
+void is_trivially_copyable2()
+{
+ int t01[T(__is_trivially_copyable(char))];
+ int t02[T(__is_trivially_copyable(int))];
+ int t03[T(__is_trivially_copyable(long))];
+ int t04[T(__is_trivially_copyable(short))];
+ int t05[T(__is_trivially_copyable(signed char))];
+ int t06[T(__is_trivially_copyable(wchar_t))];
+ int t07[T(__is_trivially_copyable(bool))];
+ int t08[T(__is_trivially_copyable(float))];
+ int t09[T(__is_trivially_copyable(double))];
+ int t10[T(__is_trivially_copyable(long double))];
+ int t11[T(__is_trivially_copyable(unsigned char))];
+ int t12[T(__is_trivially_copyable(unsigned int))];
+ int t13[T(__is_trivially_copyable(unsigned long long))];
+ int t14[T(__is_trivially_copyable(unsigned long))];
+ int t15[T(__is_trivially_copyable(unsigned short))];
+ int t16[T(__is_trivially_copyable(ClassType))];
+ int t17[T(__is_trivially_copyable(Derives))];
+ int t18[T(__is_trivially_copyable(Enum))];
+ int t19[T(__is_trivially_copyable(IntAr))];
+ int t20[T(__is_trivially_copyable(Union))];
+ int t21[T(__is_trivially_copyable(UnionAr))];
+ int t22[T(__is_trivially_copyable(TrivialStruct))];
+ int t23[T(__is_trivially_copyable(NonTrivialStruct))];
+
+ int t30[F(__is_trivially_copyable(void))];
+ int t32[F(__is_trivially_copyable(SuperNonTrivialStruct))];
+ int t31[F(__is_trivially_copyable(NonTCStruct))];
}
struct CStruct {
@@ -1027,7 +1068,7 @@ struct HasCopy {
};
struct HasMove {
- HasMove(HasMove&& cp); // expected-warning {{rvalue references}}
+ HasMove(HasMove&& cp);
};
struct HasTemplateCons {
@@ -1211,6 +1252,9 @@ void has_nothrow_copy() {
{ int arr[F(__has_nothrow_copy(cvoid))]; }
}
+template<bool b> struct assert_expr;
+template<> struct assert_expr<true> {};
+
void has_nothrow_constructor() {
{ int arr[T(__has_nothrow_constructor(Int))]; }
{ int arr[T(__has_nothrow_constructor(IntAr))]; }
@@ -1238,6 +1282,11 @@ void has_nothrow_constructor() {
{ int arr[F(__has_nothrow_constructor(void))]; }
{ int arr[F(__has_nothrow_constructor(cvoid))]; }
{ int arr[F(__has_nothrow_constructor(HasTemplateCons))]; }
+
+ // While parsing an in-class initializer, the constructor is not known to be
+ // non-throwing yet.
+ struct HasInClassInit { int n = (assert_expr<!__has_nothrow_constructor(HasInClassInit)>(), 0); };
+ { int arr[T(__has_nothrow_constructor(HasInClassInit))]; }
}
void has_virtual_destructor() {
@@ -1474,6 +1523,51 @@ void is_trivial()
{ int arr[F(__is_trivial(cvoid))]; }
}
+void is_trivially_copyable()
+{
+ { int arr[T(__is_trivially_copyable(int))]; }
+ { int arr[T(__is_trivially_copyable(Enum))]; }
+ { int arr[T(__is_trivially_copyable(POD))]; }
+ { int arr[T(__is_trivially_copyable(Int))]; }
+ { int arr[T(__is_trivially_copyable(IntAr))]; }
+ { int arr[T(__is_trivially_copyable(IntArNB))]; }
+ { int arr[T(__is_trivially_copyable(Statics))]; }
+ { int arr[T(__is_trivially_copyable(Empty))]; }
+ { int arr[T(__is_trivially_copyable(EmptyUnion))]; }
+ { int arr[T(__is_trivially_copyable(Union))]; }
+ { int arr[T(__is_trivially_copyable(Derives))]; }
+ { int arr[T(__is_trivially_copyable(DerivesAr))]; }
+ { int arr[T(__is_trivially_copyable(DerivesArNB))]; }
+ { int arr[T(__is_trivially_copyable(DerivesEmpty))]; }
+ { int arr[T(__is_trivially_copyable(HasFunc))]; }
+ { int arr[T(__is_trivially_copyable(HasOp))]; }
+ { int arr[T(__is_trivially_copyable(HasConv))]; }
+ { int arr[T(__is_trivially_copyable(HasAssign))]; }
+ { int arr[T(__is_trivially_copyable(HasAnonymousUnion))]; }
+ { int arr[T(__is_trivially_copyable(HasPriv))]; }
+ { int arr[T(__is_trivially_copyable(HasProt))]; }
+ { int arr[T(__is_trivially_copyable(DerivesHasPriv))]; }
+ { int arr[T(__is_trivially_copyable(DerivesHasProt))]; }
+ { int arr[T(__is_trivially_copyable(Vector))]; }
+ { int arr[T(__is_trivially_copyable(VectorExt))]; }
+ { int arr[T(__is_trivially_copyable(HasCons))]; }
+ { int arr[T(__is_trivially_copyable(HasRef))]; }
+ { int arr[T(__is_trivially_copyable(HasNonPOD))]; }
+ { int arr[T(__is_trivially_copyable(DerivesHasCons))]; }
+ { int arr[T(__is_trivially_copyable(DerivesHasRef))]; }
+
+ { int arr[F(__is_trivially_copyable(HasCopyAssign))]; }
+ { int arr[F(__is_trivially_copyable(HasMoveAssign))]; }
+ { int arr[F(__is_trivially_copyable(HasDest))]; }
+ { int arr[F(__is_trivially_copyable(HasVirt))]; }
+ { int arr[F(__is_trivially_copyable(DerivesHasCopyAssign))]; }
+ { int arr[F(__is_trivially_copyable(DerivesHasMoveAssign))]; }
+ { int arr[F(__is_trivially_copyable(DerivesHasDest))]; }
+ { int arr[F(__is_trivially_copyable(DerivesHasVirt))]; }
+ { int arr[F(__is_trivially_copyable(void))]; }
+ { int arr[F(__is_trivially_copyable(cvoid))]; }
+}
+
void array_rank() {
int t01[T(__array_rank(IntAr) == 1)];
int t02[T(__array_rank(ConstIntArAr) == 2)];
diff --git a/test/SemaCXX/underlying_type.cpp b/test/SemaCXX/underlying_type.cpp
new file mode 100644
index 0000000..607d9ad
--- /dev/null
+++ b/test/SemaCXX/underlying_type.cpp
@@ -0,0 +1,37 @@
+// RUN: %clang_cc1 -ffreestanding -fsyntax-only -verify -std=c++0x %s
+
+#include "limits.h"
+
+template<typename T, typename U>
+struct is_same_type {
+ static const bool value = false;
+};
+template <typename T>
+struct is_same_type<T, T> {
+ static const bool value = true;
+};
+
+__underlying_type(int) a; // expected-error {{only enumeration types}}
+__underlying_type(struct b) c; // expected-error {{only enumeration types}}
+
+enum class f : char;
+static_assert(is_same_type<char, __underlying_type(f)>::value,
+ "f has the wrong underlying type");
+
+enum g {d = INT_MIN };
+static_assert(is_same_type<int, __underlying_type(g)>::value,
+ "g has the wrong underlying type");
+
+__underlying_type(f) h;
+static_assert(is_same_type<char, decltype(h)>::value,
+ "h has the wrong type");
+
+template <typename T>
+struct underlying_type {
+ typedef __underlying_type(T) type; // expected-error {{only enumeration types}}
+};
+
+static_assert(is_same_type<underlying_type<f>::type, char>::value,
+ "f has the wrong underlying type in the template");
+
+underlying_type<int>::type e; // expected-note {{requested here}}
diff --git a/test/SemaCXX/value-initialization.cpp b/test/SemaCXX/value-initialization.cpp
index 10520fb..dfe0f46 100644
--- a/test/SemaCXX/value-initialization.cpp
+++ b/test/SemaCXX/value-initialization.cpp
@@ -1,12 +1,11 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s -std=c++0x
-struct A { // expected-error {{implicit default constructor for 'A' must explicitly initialize the const member 'i'}} \
- // expected-warning{{struct 'A' does not declare any constructor to initialize its non-modifiable members}}
- const int i; // expected-note {{declared here}} \
- // expected-note{{const member 'i' will never be initialized}}
+struct A { //expected-note {{marked deleted here}} \
+ // expected-warning {{does not declare any constructor to initialize}}
+ const int i; // expected-note{{const member 'i' will never be initialized}}
virtual void f() { }
};
int main () {
- (void)A(); // expected-note {{first required here}}
+ (void)A(); // expected-error {{call to deleted constructor}}
}
diff --git a/test/SemaCXX/vararg-non-pod.cpp b/test/SemaCXX/vararg-non-pod.cpp
index 55ec941..df0080f 100644
--- a/test/SemaCXX/vararg-non-pod.cpp
+++ b/test/SemaCXX/vararg-non-pod.cpp
@@ -56,15 +56,18 @@ void t4()
}
class E {
- E(int, ...);
+ E(int, ...); // expected-note 2{{implicitly declared private here}}
};
void t5()
{
C c(10);
- E e(10, c); // expected-warning{{cannot pass object of non-POD type 'C' through variadic constructor; call will abort at runtime}}
- (void)E(10, c); // expected-warning{{cannot pass object of non-POD type 'C' through variadic constructor; call will abort at runtime}}
+ E e(10, c); // expected-warning{{cannot pass object of non-POD type 'C' through variadic constructor; call will abort at runtime}} \
+ // expected-error{{calling a private constructor of class 'E'}}
+ (void)E(10, c); // expected-warning{{cannot pass object of non-POD type 'C' through variadic constructor; call will abort at runtime}} \
+ // expected-error{{calling a private constructor of class 'E'}}
+
}
// PR5761: unevaluated operands and the non-POD warning
diff --git a/test/SemaCXX/vtable-instantiation.cc b/test/SemaCXX/vtable-instantiation.cc
index 49949a7..2a1b989 100644
--- a/test/SemaCXX/vtable-instantiation.cc
+++ b/test/SemaCXX/vtable-instantiation.cc
@@ -1,21 +1,22 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s
-// PR8640
-template<class T1> struct C1 {
- virtual void c1() {
- T1 t1 = 3; // expected-error {{cannot initialize a variable}}
- }
-};
+namespace PR8640 {
+ template<class T1> struct C1 {
+ virtual void c1() {
+ T1 t1 = 3; // expected-error {{cannot initialize a variable}}
+ }
+ };
-template<class T2> struct C2 {
- void c2() {
- new C1<T2>(); // expected-note {{in instantiation of member function}}
- }
-};
+ template<class T2> struct C2 {
+ void c2() {
+ new C1<T2>(); // expected-note {{in instantiation of member function}}
+ }
+ };
-void f() {
- C2<int*> c2;
- c2.c2(); // expected-note {{in instantiation of member function}}
+ void f() {
+ C2<int*> c2;
+ c2.c2(); // expected-note {{in instantiation of member function}}
+ }
}
namespace PR9325 {
@@ -42,5 +43,26 @@ namespace PR9325 {
{
Target<int*>* traits = &Provider<int*>::Instance;
}
+}
+namespace PR10020 {
+ struct MG {
+ virtual void Accept(int) = 0;
+ };
+
+ template <typename Type>
+ struct GMG : MG {
+ void Accept(int i) {
+ static_cast<Type *>(0)->Accept(i); // expected-error{{member reference base}}
+ }
+ static GMG* Method() { return &singleton; } // expected-note{{in instantiation of}}
+ static GMG singleton;
+ };
+
+ template <typename Type>
+ GMG<Type> GMG<Type>::singleton;
+
+ void test(void) {
+ GMG<int>::Method(); // expected-note{{in instantiation of}}
+ }
}
diff --git a/test/SemaCXX/warn-bad-memaccess.cpp b/test/SemaCXX/warn-bad-memaccess.cpp
new file mode 100644
index 0000000..e7d095f
--- /dev/null
+++ b/test/SemaCXX/warn-bad-memaccess.cpp
@@ -0,0 +1,70 @@
+// RUN: %clang_cc1 -fsyntax-only -Wdynamic-class-memaccess -verify %s
+
+extern "C" void *memset(void *, int, unsigned);
+extern "C" void *memmove(void *s1, const void *s2, unsigned n);
+extern "C" void *memcpy(void *s1, const void *s2, unsigned n);
+
+// Several types that should not warn.
+struct S1 {} s1;
+struct S2 { int x; } s2;
+struct S3 { float x, y; S1 s[4]; void (*f)(S1**); } s3;
+
+class C1 {
+ int x, y, z;
+public:
+ void foo() {}
+} c1;
+
+struct X1 { virtual void f(); } x1;
+struct X2 : virtual S1 {} x2;
+
+void test_warn() {
+ memset(&x1, 0, sizeof x1); // \
+ // expected-warning {{destination for this 'memset' call is a pointer to dynamic class}} \
+ // expected-note {{explicitly cast the pointer to silence this warning}}
+ memset(&x2, 0, sizeof x2); // \
+ // expected-warning {{destination for this 'memset' call is a pointer to dynamic class}} \
+ // expected-note {{explicitly cast the pointer to silence this warning}}
+
+ memmove(&x1, 0, sizeof x1); // \
+ // expected-warning{{destination for this 'memmove' call is a pointer to dynamic class}} \
+ // expected-note {{explicitly cast the pointer to silence this warning}}
+ memmove(0, &x1, sizeof x1); // \
+ // expected-warning{{source of this 'memmove' call is a pointer to dynamic class}} \
+ // expected-note {{explicitly cast the pointer to silence this warning}}
+ memcpy(&x1, 0, sizeof x1); // \
+ // expected-warning{{destination for this 'memcpy' call is a pointer to dynamic class}} \
+ // expected-note {{explicitly cast the pointer to silence this warning}}
+ memcpy(0, &x1, sizeof x1); // \
+ // expected-warning{{source of this 'memcpy' call is a pointer to dynamic class}} \
+ // expected-note {{explicitly cast the pointer to silence this warning}}
+}
+
+void test_nowarn(void *void_ptr) {
+ int i, *iptr;
+ float y;
+ char c;
+
+ memset(&i, 0, sizeof i);
+ memset(&iptr, 0, sizeof iptr);
+ memset(&y, 0, sizeof y);
+ memset(&c, 0, sizeof c);
+ memset(void_ptr, 0, 42);
+ memset(&s1, 0, sizeof s1);
+ memset(&s2, 0, sizeof s2);
+ memset(&s3, 0, sizeof s3);
+ memset(&c1, 0, sizeof c1);
+
+ // Unevaluated code shouldn't warn.
+ (void)sizeof memset(&x1, 0, sizeof x1);
+
+ // Dead code shouldn't warn.
+ if (false) memset(&x1, 0, sizeof x1);
+}
+
+namespace N {
+ void *memset(void *, int, unsigned);
+ void test_nowarn() {
+ N::memset(&x1, 0, sizeof x1);
+ }
+}
diff --git a/test/SemaCXX/warn-non-pod-memset.cpp b/test/SemaCXX/warn-non-pod-memset.cpp
deleted file mode 100644
index fbdcead..0000000
--- a/test/SemaCXX/warn-non-pod-memset.cpp
+++ /dev/null
@@ -1,63 +0,0 @@
-// RUN: %clang_cc1 -fsyntax-only -Wnon-pod-memset -verify %s
-
-extern void *memset(void *, int, unsigned);
-
-// Several POD types that should not warn.
-struct S1 {} s1;
-struct S2 { int x; } s2;
-struct S3 { float x, y; S1 s[4]; void (*f)(S1**); } s3;
-
-// We use the C++11 concept of POD for this warning, so ensure a non-aggregate
-// still warns.
-class C1 {
- int x, y, z;
-public:
- void foo() {}
-} c1;
-
-// Non-POD types that should warn.
-struct X1 { X1(); } x1;
-struct X2 { ~X2(); } x2;
-struct X3 { virtual void f(); } x3;
-struct X4 : X2 {} x4;
-struct X5 : virtual S1 {} x5;
-
-void test_warn() {
- memset(&x1, 0, sizeof x1); // \
- // expected-warning {{destination for this memset call is a pointer to a non-POD type}} \
- // expected-note {{explicitly cast the pointer to silence this warning}}
- memset(&x2, 0, sizeof x2); // \
- // expected-warning {{destination for this memset call is a pointer to a non-POD type}} \
- // expected-note {{explicitly cast the pointer to silence this warning}}
- memset(&x3, 0, sizeof x3); // \
- // expected-warning {{destination for this memset call is a pointer to a non-POD type}} \
- // expected-note {{explicitly cast the pointer to silence this warning}}
- memset(&x4, 0, sizeof x4); // \
- // expected-warning {{destination for this memset call is a pointer to a non-POD type}} \
- // expected-note {{explicitly cast the pointer to silence this warning}}
- memset(&x5, 0, sizeof x5); // \
- // expected-warning {{destination for this memset call is a pointer to a non-POD type}} \
- // expected-note {{explicitly cast the pointer to silence this warning}}
-}
-
-void test_nowarn(void *void_ptr) {
- int i, *iptr;
- float y;
- char c;
-
- memset(&i, 0, sizeof i);
- memset(&iptr, 0, sizeof iptr);
- memset(&y, 0, sizeof y);
- memset(&c, 0, sizeof c);
- memset(void_ptr, 0, 42);
- memset(&s1, 0, sizeof s1);
- memset(&s2, 0, sizeof s2);
- memset(&s3, 0, sizeof s3);
- memset(&c1, 0, sizeof c1);
-
- // Unevaluated code shouldn't warn.
- (void)sizeof memset(&x1, 0, sizeof x1);
-
- // Dead code shouldn't warn.
- if (false) memset(&x1, 0, sizeof x1);
-}
diff --git a/test/SemaCXX/warn-pure-virtual-call-from-ctor-dtor.cpp b/test/SemaCXX/warn-pure-virtual-call-from-ctor-dtor.cpp
new file mode 100644
index 0000000..698eccd
--- /dev/null
+++ b/test/SemaCXX/warn-pure-virtual-call-from-ctor-dtor.cpp
@@ -0,0 +1,7 @@
+// RUN: %clang_cc1 %s -fsyntax-only -verify
+struct A {
+ A() { f(); } // expected-warning {{call to pure virtual member function 'f'; overrides of 'f' in subclasses are not available in the constructor of 'A'}}
+ ~A() { f(); } // expected-warning {{call to pure virtual member function 'f'; overrides of 'f' in subclasses are not available in the destructor of 'A'}}
+
+ virtual void f() = 0; // expected-note 2 {{'f' declared here}}
+};
diff --git a/test/SemaObjC/exprs.m b/test/SemaObjC/exprs.m
index d7c1223..2b505e0 100644
--- a/test/SemaObjC/exprs.m
+++ b/test/SemaObjC/exprs.m
@@ -32,3 +32,13 @@ void test3(Object *o) {
// this is ok.
__sync_bool_compare_and_swap(&g, 0, o);
}
+
+@class Incomplete_ObjC_class;
+struct Incomplete_struct; // expected-note {{forward declaration}}
+
+void test_encode() {
+ (void)@encode(Incomplete_ObjC_class); // expected-error {{incomplete type}}
+ (void)@encode(struct Incomplete_struct); // expected-error {{incomplete type}}
+ (void)@encode(Incomplete_ObjC_class*);
+ (void)@encode(id);
+}
diff --git a/test/SemaObjC/gc-attributes.m b/test/SemaObjC/gc-attributes.m
new file mode 100644
index 0000000..2f54328
--- /dev/null
+++ b/test/SemaObjC/gc-attributes.m
@@ -0,0 +1,22 @@
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fobjc-gc -fsyntax-only -verify %s
+
+@interface A
+@end
+
+void f0(__strong A**); // expected-note{{passing argument to parameter here}}
+
+void test_f0() {
+ A *a;
+ static __weak A *a2;
+ f0(&a);
+ f0(&a2); // expected-warning{{passing 'A *__weak *' to parameter of type 'A *__strong *' discards qualifiers}}
+}
+
+void f1(__weak A**); // expected-note{{passing argument to parameter here}}
+
+void test_f1() {
+ A *a;
+ __strong A *a2;
+ f1(&a);
+ f1(&a2); // expected-warning{{passing 'A *__strong *' to parameter of type 'A *__weak *' discards qualifiers}}
+}
diff --git a/test/SemaObjC/objc2-warn-weak-decl.m b/test/SemaObjC/objc2-warn-weak-decl.m
index 22a3fca..b85f768 100644
--- a/test/SemaObjC/objc2-warn-weak-decl.m
+++ b/test/SemaObjC/objc2-warn-weak-decl.m
@@ -6,6 +6,6 @@ struct S {
int main ()
{
- __weak id local; // expected-warning {{__weak attribute cannot be specified on an automatic variable}}
+ __weak id local; // expected-warning {{Objective-C GC does not allow weak variables on the stack}}
}
diff --git a/test/SemaObjC/related-result-type-inference.m b/test/SemaObjC/related-result-type-inference.m
new file mode 100644
index 0000000..f539918
--- /dev/null
+++ b/test/SemaObjC/related-result-type-inference.m
@@ -0,0 +1,171 @@
+// RUN: %clang_cc1 -fobjc-infer-related-result-type -verify %s
+
+@interface Unrelated
+@end
+
+@interface NSObject
++ (id)new;
++ (id)alloc;
+- (NSObject *)init;
+
+- (id)retain; // expected-note{{instance method 'retain' is assumed to return an instance of its receiver type ('NSArray *')}}
+- autorelease;
+
+- (id)self;
+
+- (id)copy;
+- (id)mutableCopy;
+
+// Do not infer when instance/class mismatches
+- (id)newNotInferred;
+- (id)alloc;
++ (id)initWithBlarg;
++ (id)self;
+
+// Do not infer when the return types mismatch.
+- (Unrelated *)initAsUnrelated;
+@end
+
+@interface NSString : NSObject
+- (id)init;
+- (id)initWithCString:(const char*)string;
+@end
+
+@interface NSArray : NSObject
+- (unsigned)count;
+@end
+
+@interface NSBlah
+@end
+
+@interface NSMutableArray : NSArray
+@end
+
+@interface NSBlah ()
++ (Unrelated *)newUnrelated;
+@end
+
+void test_inference() {
+ // Inference based on method family
+ __typeof__(([[NSString alloc] init])) *str = (NSString**)0;
+ __typeof__(([[[[NSString new] self] retain] autorelease])) *str2 = (NSString **)0;
+ __typeof__(([[NSString alloc] initWithCString:"blah"])) *str3 = (NSString**)0;
+
+ // Not inferred
+ __typeof__(([[NSString new] copy])) *id1 = (id*)0;
+
+ // Not inferred due to instance/class mismatches
+ __typeof__(([[NSString new] newNotInferred])) *id2 = (id*)0;
+ __typeof__(([[NSString new] alloc])) *id3 = (id*)0;
+ __typeof__(([NSString self])) *id4 = (id*)0;
+ __typeof__(([NSString initWithBlarg])) *id5 = (id*)0;
+
+ // Not inferred due to return type mismatch
+ __typeof__(([[NSString alloc] initAsUnrelated])) *unrelated = (Unrelated**)0;
+ __typeof__(([NSBlah newUnrelated])) *unrelated2 = (Unrelated**)0;
+
+
+ NSArray *arr = [[NSMutableArray alloc] init];
+ NSMutableArray *marr = [arr retain]; // expected-warning{{incompatible pointer types initializing 'NSMutableArray *' with an expression of type 'NSArray *'}}
+}
+
+@implementation NSBlah
++ (Unrelated *)newUnrelated {
+ return (Unrelated *)0;
+}
+@end
+
+@implementation NSBlah (Cat)
++ (Unrelated *)newUnrelated2 {
+ return (Unrelated *)0;
+}
+@end
+
+@interface A
+- (id)initBlah; // expected-note 2{{overridden method is part of the 'init' method family}}
+@end
+
+@interface B : A
+- (Unrelated *)initBlah; // expected-warning{{method is expected to return an instance of its class type 'B', but is declared to return 'Unrelated *'}}
+@end
+
+@interface C : A
+@end
+
+@implementation C
+- (Unrelated *)initBlah { // expected-warning{{method is expected to return an instance of its class type 'C', but is declared to return 'Unrelated *'}}
+ return (Unrelated *)0;
+}
+@end
+
+@interface D
++ (id)newBlarg; // expected-note{{overridden method is part of the 'new' method family}}
+@end
+
+@interface D ()
++ alloc; // expected-note{{overridden method is part of the 'alloc' method family}}
+@end
+
+@implementation D
++ (Unrelated *)newBlarg { // expected-warning{{method is expected to return an instance of its class type 'D', but is declared to return 'Unrelated *'}}
+ return (Unrelated *)0;
+}
+
++ (Unrelated *)alloc { // expected-warning{{method is expected to return an instance of its class type 'D', but is declared to return 'Unrelated *'}}
+ return (Unrelated *)0;
+}
+@end
+
+@protocol P1
+- (id)initBlah; // expected-note{{overridden method is part of the 'init' method family}}
+- (int)initBlarg;
+@end
+
+@protocol P2 <P1>
+- (int)initBlah; // expected-warning{{protocol method is expected to return an instance of the implementing class, but is declared to return 'int'}}
+- (int)initBlarg;
+- (int)initBlech;
+@end
+
+@interface E
+- init;
+@end
+
+@implementation E
+- init {
+ return self;
+}
+@end
+
+@protocol P3
++ (NSString *)newString;
+@end
+
+@interface F<P3>
+@end
+
+@implementation F
++ (NSString *)newString { return @"blah"; }
+@end
+
+// <rdar://problem/9340699>
+@interface G
+- (id)_ABC_init __attribute__((objc_method_family(init)));
+@end
+
+@interface G (Additions)
+- (id)_ABC_init2 __attribute__((objc_method_family(init)));
+@end
+
+@implementation G (Additions)
+- (id)_ABC_init {
+ return 0;
+}
+- (id)_ABC_init2 {
+ return 0;
+}
+- (id)_ABC_init3 {
+ return 0;
+}
+@end
+
diff --git a/test/SemaObjCXX/blocks.mm b/test/SemaObjCXX/blocks.mm
index 6c2343d..c91fd10 100644
--- a/test/SemaObjCXX/blocks.mm
+++ b/test/SemaObjCXX/blocks.mm
@@ -118,3 +118,29 @@ void f(int (^bl)(A* a)); // expected-note {{candidate function not viable: no kn
void g() {
f(^(B* b) { return 0; }); // expected-error {{no matching function for call to 'f'}}
}
+
+namespace DependentReturn {
+ template<typename T>
+ void f(T t) {
+ (void)^(T u) {
+ if (t != u)
+ return t + u;
+ else
+ return;
+ };
+
+ (void)^(T u) {
+ if (t == u)
+ return;
+ else
+ return t + u;
+ };
+ }
+
+ struct X { };
+ void operator+(X, X);
+ bool operator==(X, X);
+ bool operator!=(X, X);
+
+ template void f<X>(X);
+}
diff --git a/test/SemaObjCXX/gc-attributes.mm b/test/SemaObjCXX/gc-attributes.mm
new file mode 100644
index 0000000..70a93b2
--- /dev/null
+++ b/test/SemaObjCXX/gc-attributes.mm
@@ -0,0 +1,22 @@
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fobjc-gc -fsyntax-only -verify %s
+
+@interface A
+@end
+
+void f0(__strong A**); // expected-note{{candidate function not viable: 1st argument ('A *__weak *') has __weak lifetime, but parameter has __strong lifetime}}
+
+void test_f0() {
+ A *a;
+ static __weak A *a2;
+ f0(&a);
+ f0(&a2); // expected-error{{no matching function}}
+}
+
+void f1(__weak A**); // expected-note{{candidate function not viable: 1st argument ('A *__strong *') has __strong lifetime, but parameter has __weak lifetime}}
+
+void test_f1() {
+ A *a;
+ __strong A *a2;
+ f1(&a);
+ f1(&a2); // expected-error{{no matching function}}
+}
diff --git a/test/SemaObjCXX/namespace-lookup.mm b/test/SemaObjCXX/namespace-lookup.mm
new file mode 100644
index 0000000..205b443
--- /dev/null
+++ b/test/SemaObjCXX/namespace-lookup.mm
@@ -0,0 +1,14 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s
+
+// <rdar://problem/9388207>
+@interface A
+@end
+
+@interface A(N)
+@end
+
+@protocol M
+@end
+
+namespace N { }
+namespace M { }
diff --git a/test/SemaObjCXX/nullptr.mm b/test/SemaObjCXX/nullptr.mm
new file mode 100644
index 0000000..4cd5669
--- /dev/null
+++ b/test/SemaObjCXX/nullptr.mm
@@ -0,0 +1,13 @@
+// RUN: %clang_cc1 -std=c++0x -fsyntax-only -verify %s
+
+@interface A
+@end
+
+void comparisons(A *a) {
+ (void)(a == nullptr);
+ (void)(nullptr == a);
+}
+
+void assignment(A *a) {
+ a = nullptr;
+}
diff --git a/test/SemaObjCXX/overload-gc.mm b/test/SemaObjCXX/overload-gc.mm
index d2ddd40..5488ea5 100644
--- a/test/SemaObjCXX/overload-gc.mm
+++ b/test/SemaObjCXX/overload-gc.mm
@@ -1,9 +1,9 @@
// RUN: %clang_cc1 -fsyntax-only -triple i386-apple-darwin9 -fobjc-gc -verify %s
-void f0(__weak id *); // expected-note{{candidate function not viable: 1st argument ('id *') has no lifetime, but parameter has __weak lifetime}}
+void f0(__weak id *);
void test_f0(id *x) {
- f0(x); // expected-error{{no matching function for call to 'f0'}}
+ f0(x);
}
@interface A
diff --git a/test/SemaObjCXX/overload.mm b/test/SemaObjCXX/overload.mm
index 960a7b2..ea5f0e5 100644
--- a/test/SemaObjCXX/overload.mm
+++ b/test/SemaObjCXX/overload.mm
@@ -52,12 +52,12 @@ void test0(A* a, B* b, id val) {
void test1(A* a) {
B* b = a; // expected-warning{{incompatible pointer types initializing 'B *' with an expression of type 'A *'}}
- B *c; c = a; // expected-warning{{incompatible pointer types assigning to 'A *' from 'B *'}}
+ B *c; c = a; // expected-warning{{incompatible pointer types assigning to 'B *' from 'A *'}}
}
void test2(A** ap) {
B** bp = ap; // expected-warning{{incompatible pointer types initializing 'B **' with an expression of type 'A **'}}
- bp = ap; // expected-warning{{incompatible pointer types assigning to 'A **' from 'B **'}}
+ bp = ap; // expected-warning{{incompatible pointer types assigning to 'B **' from 'A **'}}
}
// FIXME: we should either allow overloading here or give a better diagnostic
diff --git a/test/SemaObjCXX/related-result-type-inference.mm b/test/SemaObjCXX/related-result-type-inference.mm
new file mode 100644
index 0000000..c3cab05
--- /dev/null
+++ b/test/SemaObjCXX/related-result-type-inference.mm
@@ -0,0 +1,71 @@
+// RUN: %clang_cc1 -fobjc-infer-related-result-type -verify %s
+
+@interface Unrelated
+@end
+
+@interface NSObject
++ (id)new;
++ (id)alloc;
+- (NSObject *)init;
+
+- (id)retain; // expected-note 2{{instance method 'retain' is assumed to return an instance of its receiver type ('NSArray *')}}
+- autorelease;
+
+- (id)self;
+
+- (id)copy;
+- (id)mutableCopy;
+
+// Do not infer when instance/class mismatches
+- (id)newNotInferred;
+- (id)alloc;
++ (id)initWithBlarg;
++ (id)self;
+
+// Do not infer when the return types mismatch.
+- (Unrelated *)initAsUnrelated;
+@end
+
+@interface NSString : NSObject
+- (id)init;
+- (id)initWithCString:(const char*)string;
+@end
+
+@interface NSArray : NSObject
+- (unsigned)count;
+@end
+
+@interface NSBlah
+@end
+
+@interface NSMutableArray : NSArray
+@end
+
+@interface NSBlah ()
++ (Unrelated *)newUnrelated;
+@end
+
+void test_inference() {
+ // Inference based on method family
+ __typeof__(([[NSString alloc] init])) *str = (NSString**)0;
+ __typeof__(([[[[NSString new] self] retain] autorelease])) *str2 = (NSString **)0;
+ __typeof__(([[NSString alloc] initWithCString:"blah"])) *str3 = (NSString**)0;
+
+ // Not inferred
+ __typeof__(([[NSString new] copy])) *id1 = (id*)0;
+
+ // Not inferred due to instance/class mismatches
+ __typeof__(([[NSString new] newNotInferred])) *id2 = (id*)0;
+ __typeof__(([[NSString new] alloc])) *id3 = (id*)0;
+ __typeof__(([NSString self])) *id4 = (id*)0;
+ __typeof__(([NSString initWithBlarg])) *id5 = (id*)0;
+
+ // Not inferred due to return type mismatch
+ __typeof__(([[NSString alloc] initAsUnrelated])) *unrelated = (Unrelated**)0;
+ __typeof__(([NSBlah newUnrelated])) *unrelated2 = (Unrelated**)0;
+
+ NSArray *arr = [[NSMutableArray alloc] init];
+ NSMutableArray *marr = [arr retain]; // expected-warning{{incompatible pointer types initializing 'NSMutableArray *' with an expression of type 'NSArray *'}}
+ marr = [arr retain]; // expected-warning{{incompatible pointer types assigning to 'NSMutableArray *' from 'NSArray *'}}
+ arr = [marr retain];
+}
diff --git a/test/SemaTemplate/alias-church-numerals.cpp b/test/SemaTemplate/alias-church-numerals.cpp
new file mode 100644
index 0000000..751cac7
--- /dev/null
+++ b/test/SemaTemplate/alias-church-numerals.cpp
@@ -0,0 +1,34 @@
+// RUN: %clang_cc1 -std=c++0x -fsyntax-only -verify %s
+
+template<template<template<typename> class, typename> class T, template<typename> class V> struct PartialApply {
+ template<typename W> using R = T<V, W>;
+};
+
+template<typename T> using Id = T;
+template<template<typename> class, typename X> using Zero = X;
+template<template<template<typename> class, typename> class N, template<typename> class F, typename X> using Succ = F<N<F,X>>;
+
+template<template<typename> class F, typename X> using One = Succ<Zero, F, X>;
+template<template<typename> class F, typename X> using Two = Succ<One, F, X>;
+
+template<template<template<typename> class, typename> class A,
+ template<template<typename> class, typename> class B,
+ template<typename> class F,
+ typename X> using Add = A<F, B<F, X>>;
+
+template<template<template<typename> class, typename> class A,
+ template<template<typename> class, typename> class B,
+ template<typename> class F,
+ typename X> using Mul = A<PartialApply<B,F>::template R, X>;
+
+template<template<typename> class F, typename X> using Four = Add<Two, Two, F, X>;
+template<template<typename> class F, typename X> using Sixteen = Mul<Four, Four, F, X>;
+template<template<typename> class F, typename X> using TwoHundredAndFiftySix = Mul<Sixteen, Sixteen, F, X>;
+
+template<typename T, T N> struct Const { static const T value = N; };
+template<typename A> struct IncrementHelper;
+template<typename T, T N> struct IncrementHelper<Const<T, N>> { using Result = Const<T, N+1>; };
+template<typename A> using Increment = typename IncrementHelper<A>::Result;
+
+using Arr = int[TwoHundredAndFiftySix<Increment, Const<int, 0>>::value];
+using Arr = int[256];
diff --git a/test/SemaTemplate/alias-nested-nontag.cpp b/test/SemaTemplate/alias-nested-nontag.cpp
new file mode 100644
index 0000000..1bb5ce3
--- /dev/null
+++ b/test/SemaTemplate/alias-nested-nontag.cpp
@@ -0,0 +1,6 @@
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++0x %s
+
+template<typename T> using Id = T; // expected-note {{type alias template 'Id' declared here}}
+struct U { static Id<int> V; };
+Id<int> ::U::V; // expected-error {{type 'Id<int>' (aka 'int') cannot be used prior to '::' because it has no members}} \
+ expected-error {{C++ requires a type specifier}}
diff --git a/test/SemaTemplate/alias-template-template-param.cpp b/test/SemaTemplate/alias-template-template-param.cpp
new file mode 100644
index 0000000..a847b06
--- /dev/null
+++ b/test/SemaTemplate/alias-template-template-param.cpp
@@ -0,0 +1,7 @@
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++0x %s
+
+template<template<typename> class D> using C = D<int>;
+
+// Substitution of the alias template transforms the TemplateSpecializationType
+// 'D<int>' into the DependentTemplateSpecializationType 'T::template U<int>'.
+template<typename T> void f(C<T::template U>);
diff --git a/test/SemaTemplate/alias-templates.cpp b/test/SemaTemplate/alias-templates.cpp
new file mode 100644
index 0000000..f4c917c
--- /dev/null
+++ b/test/SemaTemplate/alias-templates.cpp
@@ -0,0 +1,70 @@
+// RUN: %clang_cc1 -std=c++0x -fsyntax-only -verify %s
+
+template<typename S>
+struct A {
+ typedef S B;
+ template<typename T> using C = typename T::B;
+ template<typename T> struct D {
+ template<typename U> using E = typename A<U>::template C<A<T>>;
+ template<typename U> using F = A<E<U>>;
+ template<typename U> using G = C<F<U>>;
+ G<T> g;
+ };
+ typedef decltype(D<B>().g) H;
+ D<H> h;
+ template<typename T> using I = A<decltype(h.g)>;
+ template<typename T> using J = typename A<decltype(h.g)>::template C<I<T>>;
+};
+
+A<int> a;
+A<char>::D<double> b;
+
+template<typename T> T make();
+
+namespace X {
+ template<typename T> struct traits {
+ typedef T thing;
+ typedef decltype(val(make<thing>())) inner_ptr;
+
+ template<typename U> using rebind_thing = typename thing::template rebind<U>;
+ template<typename U> using rebind = traits<rebind_thing<U>>;
+
+ inner_ptr &&alloc();
+ void free(inner_ptr&&);
+ };
+
+ template<typename T> struct ptr_traits {
+ typedef T *type;
+ };
+ template<typename T> using ptr = typename ptr_traits<T>::type;
+
+ template<typename T> struct thing {
+ typedef T inner;
+ typedef ptr<inner> inner_ptr;
+ typedef traits<thing<inner>> traits_type;
+
+ template<typename U> using rebind = thing<U>;
+
+ thing(traits_type &traits) : traits(traits), val(traits.alloc()) {}
+ ~thing() { traits.free(static_cast<inner_ptr&&>(val)); }
+
+ traits_type &traits;
+ inner_ptr val;
+
+ friend inner_ptr val(const thing &t) { return t.val; }
+ };
+
+ template<> struct ptr_traits<bool> {
+ typedef bool &type;
+ };
+ template<> bool &traits<thing<bool>>::alloc() { static bool b; return b; }
+ template<> void traits<thing<bool>>::free(bool&) {}
+}
+
+typedef X::traits<X::thing<int>> itt;
+
+itt::thing::traits_type itr;
+itt::thing ith(itr);
+
+itt::rebind<bool> btr;
+itt::rebind_thing<bool> btt(btr);
diff --git a/test/SemaTemplate/deduction-crash.cpp b/test/SemaTemplate/deduction-crash.cpp
index ec97311..fb23eda 100644
--- a/test/SemaTemplate/deduction-crash.cpp
+++ b/test/SemaTemplate/deduction-crash.cpp
@@ -1,10 +1,10 @@
// RUN: %clang_cc1 -fsyntax-only %s 2>&1| FileCheck %s
-// PR7511
-
// Note that the error count below doesn't matter. We just want to
// make sure that the parser doesn't crash.
-// CHECK: 13 errors
+// CHECK: 14 errors
+
+// PR7511
template<a>
struct int_;
@@ -57,3 +57,33 @@ int a()
state_machine<int> p;
p.ant(0);
}
+
+// PR9974
+template <int> struct enable_if;
+template <class > struct remove_reference ;
+template <class _Tp> struct remove_reference<_Tp&> ;
+
+template <class > struct __tuple_like;
+
+template <class _Tp, class _Up, int = __tuple_like<typename remove_reference<_Tp>::type>::value>
+struct __tuple_convertible;
+
+struct pair
+{
+template<class _Tuple, int = enable_if<__tuple_convertible<_Tuple, pair>::value>::type>
+pair(_Tuple&& );
+};
+
+template <class> struct basic_ostream;
+
+template <int>
+void endl( ) ;
+
+extern basic_ostream<char> cout;
+
+int operator<<( basic_ostream<char> , pair ) ;
+
+void register_object_imp ( )
+{
+cout << endl<1>;
+}
diff --git a/test/SemaTemplate/dependent-names-no-std.cpp b/test/SemaTemplate/dependent-names-no-std.cpp
new file mode 100644
index 0000000..e9ac99f
--- /dev/null
+++ b/test/SemaTemplate/dependent-names-no-std.cpp
@@ -0,0 +1,21 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s
+//
+// The whole point of this test is to verify certain diagnostics work in the
+// absence of namespace 'std'.
+
+namespace PR10053 {
+ namespace ns {
+ struct Data {};
+ }
+
+ template<typename T> struct A {
+ T t;
+ A() {
+ f(t); // expected-error {{call to function 'f' that is neither visible in the template definition nor found by argument dependent lookup}}
+ }
+ };
+
+ void f(ns::Data); // expected-note {{in namespace 'PR10053::ns'}}
+
+ A<ns::Data> a; // expected-note {{in instantiation of member function}}
+}
diff --git a/test/SemaTemplate/dependent-names.cpp b/test/SemaTemplate/dependent-names.cpp
index 5776ddc..2a50df5 100644
--- a/test/SemaTemplate/dependent-names.cpp
+++ b/test/SemaTemplate/dependent-names.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -verify %s
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++0x %s
typedef double A;
template<typename T> class B {
@@ -129,3 +129,136 @@ namespace PR8966 {
template <class T>
const char* MyClass<T>::array [MyClass<T>::N] = { "A", "B", "C" };
}
+
+namespace std {
+ inline namespace v1 {
+ template<typename T> struct basic_ostream;
+ }
+ namespace inner {
+ template<typename T> struct vector {};
+ }
+ using inner::vector;
+ template<typename T, typename U> struct pair {};
+ typedef basic_ostream<char> ostream;
+ extern ostream cout;
+ std::ostream &operator<<(std::ostream &out, const char *);
+}
+
+namespace PR10053 {
+ template<typename T> struct A {
+ T t;
+ A() {
+ f(t); // expected-error {{call to function 'f' that is neither visible in the template definition nor found by argument dependent lookup}}
+ }
+ };
+
+ void f(int&); // expected-note {{'f' should be declared prior to the call site}}
+
+ A<int> a; // expected-note {{in instantiation of member function}}
+
+
+ namespace N {
+ namespace M {
+ template<typename T> int g(T t) {
+ f(t); // expected-error {{call to function 'f' that is neither visible in the template definition nor found by argument dependent lookup}}
+ };
+ }
+
+ void f(char&); // expected-note {{'f' should be declared prior to the call site}}
+ }
+
+ void f(char&);
+
+ int k = N::M::g<char>(0);; // expected-note {{in instantiation of function}}
+
+
+ namespace O {
+ void f(char&); // expected-note {{candidate function not viable}}
+
+ template<typename T> struct C {
+ static const int n = f(T()); // expected-error {{no matching function}}
+ };
+ }
+
+ int f(double); // no note, shadowed by O::f
+ O::C<double> c; // expected-note {{requested here}}
+
+
+ // Example from www/compatibility.html
+ namespace my_file {
+ template <typename T> T Squared(T x) {
+ return Multiply(x, x); // expected-error {{neither visible in the template definition nor found by argument dependent lookup}}
+ }
+
+ int Multiply(int x, int y) { // expected-note {{should be declared prior to the call site}}
+ return x * y;
+ }
+
+ int main() {
+ Squared(5); // expected-note {{here}}
+ }
+ }
+
+ // Example from www/compatibility.html
+ namespace my_file2 {
+ template<typename T>
+ void Dump(const T& value) {
+ std::cout << value << "\n"; // expected-error {{neither visible in the template definition nor found by argument dependent lookup}}
+ }
+
+ namespace ns {
+ struct Data {};
+ }
+
+ std::ostream& operator<<(std::ostream& out, ns::Data data) { // expected-note {{should be declared prior to the call site or in namespace 'PR10053::my_file2::ns'}}
+ return out << "Some data";
+ }
+
+ void Use() {
+ Dump(ns::Data()); // expected-note {{here}}
+ }
+ }
+
+ namespace my_file2_a {
+ template<typename T>
+ void Dump(const T &value) {
+ print(std::cout, value); // expected-error 4{{neither visible in the template definition nor found by argument dependent lookup}}
+ }
+
+ namespace ns {
+ struct Data {};
+ }
+ namespace ns2 {
+ struct Data {};
+ }
+
+ std::ostream &print(std::ostream &out, int); // expected-note-re {{should be declared prior to the call site$}}
+ std::ostream &print(std::ostream &out, ns::Data); // expected-note {{should be declared prior to the call site or in namespace 'PR10053::my_file2_a::ns'}}
+ std::ostream &print(std::ostream &out, std::vector<ns2::Data>); // expected-note {{should be declared prior to the call site or in namespace 'PR10053::my_file2_a::ns2'}}
+ std::ostream &print(std::ostream &out, std::pair<ns::Data, ns2::Data>); // expected-note {{should be declared prior to the call site or in an associated namespace of one of its arguments}}
+
+ void Use() {
+ Dump(0); // expected-note {{requested here}}
+ Dump(ns::Data()); // expected-note {{requested here}}
+ Dump(std::vector<ns2::Data>()); // expected-note {{requested here}}
+ Dump(std::pair<ns::Data, ns2::Data>()); // expected-note {{requested here}}
+ }
+ }
+
+ namespace unary {
+ template<typename T>
+ T Negate(const T& value) {
+ return !value; // expected-error {{call to function 'operator!' that is neither visible in the template definition nor found by argument dependent lookup}}
+ }
+
+ namespace ns {
+ struct Data {};
+ }
+
+ ns::Data operator!(ns::Data); // expected-note {{should be declared prior to the call site or in namespace 'PR10053::unary::ns'}}
+
+ void Use() {
+ Negate(ns::Data()); // expected-note {{requested here}}
+ }
+ }
+}
diff --git a/test/SemaTemplate/friend-template.cpp b/test/SemaTemplate/friend-template.cpp
index 703daea..d1284de 100644
--- a/test/SemaTemplate/friend-template.cpp
+++ b/test/SemaTemplate/friend-template.cpp
@@ -216,3 +216,11 @@ namespace PR8649 {
X<int, float, 7> x;
}
+
+// Don't crash, and error on invalid friend type template.
+namespace friend_type_template_no_tag {
+ template <typename T> struct S {
+ template <typename U> friend S<U>; // expected-error{{friend type templates must use an elaborated type}}
+ };
+ template struct S<int>;
+}
diff --git a/test/SemaTemplate/instantiate-call.cpp b/test/SemaTemplate/instantiate-call.cpp
index ad06be3..a0e48c8 100644
--- a/test/SemaTemplate/instantiate-call.cpp
+++ b/test/SemaTemplate/instantiate-call.cpp
@@ -24,7 +24,8 @@ namespace N3 {
template<typename T, typename Result>
struct call_f0 {
void test_f0(T t) {
- Result &result = f0(t); // expected-error 2{{undeclared identifier}}
+ Result &result = f0(t); // expected-error {{undeclared identifier}} \
+ expected-error {{neither visible in the template definition nor found by argument dependent lookup}}
}
};
}
@@ -32,7 +33,7 @@ namespace N3 {
template struct N3::call_f0<int, char&>; // expected-note{{instantiation}}
template struct N3::call_f0<N1::X0, int&>;
-short& f0(char);
+short& f0(char); // expected-note {{should be declared prior to the call site}}
namespace N4 {
template<typename T, typename Result>
struct call_f0 {
diff --git a/test/SemaTemplate/instantiate-function-1.cpp b/test/SemaTemplate/instantiate-function-1.cpp
index 688d009..5406fbc 100644
--- a/test/SemaTemplate/instantiate-function-1.cpp
+++ b/test/SemaTemplate/instantiate-function-1.cpp
@@ -225,3 +225,25 @@ namespace PR7016 {
template<typename T> void f() { T x = x; }
template void f<int>();
}
+
+namespace PR9880 {
+ struct lua_State;
+ struct no_tag { char a; }; // (A)
+ struct yes_tag { long a; long b; }; // (A)
+
+ template <typename T>
+ struct HasIndexMetamethod {
+ template <typename U>
+ static no_tag check(...);
+ template <typename U>
+ static yes_tag check(char[sizeof(&U::luaIndex)]);
+ enum { value = sizeof(check<T>(0)) == sizeof(yes_tag) };
+ };
+
+ class SomeClass {
+ public:
+ int luaIndex(lua_State* L);
+ };
+
+ int i = HasIndexMetamethod<SomeClass>::value;
+}
diff --git a/test/SemaTemplate/instantiate-init.cpp b/test/SemaTemplate/instantiate-init.cpp
index e292aa3..f0ca9a5 100644
--- a/test/SemaTemplate/instantiate-init.cpp
+++ b/test/SemaTemplate/instantiate-init.cpp
@@ -55,3 +55,55 @@ namespace PR6657 {
f0<int>();
}
}
+
+// Instantiate out-of-line definitions of static data members which complete
+// types through an initializer even when the only use of the member that would
+// cause instantiation is in an unevaluated context, but one requiring its
+// complete type.
+namespace PR10001 {
+ template <typename T> struct S {
+ static const int arr[];
+ static const int x;
+ static int f();
+ };
+
+ template <typename T> const int S<T>::arr[] = { 1, 2, 3 };
+ template <typename T> const int S<T>::x = sizeof(arr) / sizeof(arr[0]);
+ template <typename T> int S<T>::f() { return x; }
+
+ int x = S<int>::f();
+}
+
+namespace PR7985 {
+ template<int N> struct integral_c { };
+
+ template <typename T, int N>
+ integral_c<N> array_lengthof(T (&x)[N]) { return integral_c<N>(); } // expected-note 2{{candidate template ignored: failed template argument deduction}}
+
+ template<typename T>
+ struct Data {
+ T x;
+ };
+
+ template<typename T>
+ struct Description {
+ static const Data<T> data[];
+ };
+
+ template<typename T>
+ const Data<T> Description<T>::data[] = {{ 1 }}; // expected-error{{cannot initialize a member subobject of type 'int *' with an rvalue of type 'int'}}
+
+ template<>
+ Data<float*> Description<float*>::data[];
+
+ void test() {
+ integral_c<1> ic1 = array_lengthof(Description<int>::data);
+ (void)sizeof(array_lengthof(Description<float>::data));
+
+ sizeof(array_lengthof( // expected-error{{no matching function for call to 'array_lengthof'}}
+ Description<int*>::data // expected-note{{in instantiation of static data member 'PR7985::Description<int *>::data' requested here}}
+ ));
+
+ array_lengthof(Description<float*>::data); // expected-error{{no matching function for call to 'array_lengthof'}}
+ }
+}
diff --git a/test/SemaTemplate/partial-spec-instantiate.cpp b/test/SemaTemplate/partial-spec-instantiate.cpp
index 68b4964..a93af50 100644
--- a/test/SemaTemplate/partial-spec-instantiate.cpp
+++ b/test/SemaTemplate/partial-spec-instantiate.cpp
@@ -38,3 +38,13 @@ namespace WonkyAccess {
return y.m + y2.m;
}
}
+
+// <rdar://problem/9169404>
+namespace rdar9169404 {
+ template<typename T, T N> struct X { };
+ template<bool C> struct X<bool, C> {
+ typedef int type;
+ };
+
+ X<bool, -1>::type value;
+}
diff --git a/test/SemaTemplate/rdar9173693.cpp b/test/SemaTemplate/rdar9173693.cpp
new file mode 100644
index 0000000..86b4954
--- /dev/null
+++ b/test/SemaTemplate/rdar9173693.cpp
@@ -0,0 +1,6 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s
+
+// <rdar://problem/9173693>
+template< bool C > struct assert { };
+template< bool > struct assert_arg_pred_impl { }; // expected-note 3 {{declared here}}
+template< typename Pred > assert<false> assert_not_arg( void (*)(Pred), typename assert_arg_pred<Pred>::type ); // expected-error 5 {{}}
diff --git a/test/SemaTemplate/typename-specifier.cpp b/test/SemaTemplate/typename-specifier.cpp
index 4c788f6..7898a20 100644
--- a/test/SemaTemplate/typename-specifier.cpp
+++ b/test/SemaTemplate/typename-specifier.cpp
@@ -71,3 +71,34 @@ struct C {
::Y<A>::type ip7 = &i;
::Y<B>::type ip8 = &i; // expected-note{{in instantiation of template class 'Y<B>' requested here}}
::Y<C>::type ip9 = &i; // expected-note{{in instantiation of template class 'Y<C>' requested here}}
+
+template<typename T> struct D {
+ typedef typename T::foo foo; // expected-error {{type 'long' cannot be used prior to '::' because it has no members}}
+ typedef typename foo::bar bar;
+};
+
+D<long> struct_D; // expected-note {{in instantiation of template class 'D<long>' requested here}}
+
+template<typename T> struct E {
+ typedef typename T::foo foo;
+ typedef typename foo::bar bar; // expected-error {{type 'foo' (aka 'double') cannot be used prior to '::' because it has no members}}
+};
+
+struct F {
+ typedef double foo;
+};
+
+E<F> struct_E; // expected-note {{in instantiation of template class 'E<F>' requested here}}
+
+template<typename T> struct G {
+ typedef typename T::foo foo;
+ typedef typename foo::bar bar;
+};
+
+struct H {
+ struct foo {
+ typedef double bar;
+ };
+};
+
+G<H> struct_G;
diff --git a/test/lit.cfg b/test/lit.cfg
index 4b9d529..e18105d 100644
--- a/test/lit.cfg
+++ b/test/lit.cfg
@@ -171,3 +171,33 @@ if platform.system() != 'Windows':
# Shell execution
if platform.system() not in ['Windows'] or lit.getBashPath() != '':
config.available_features.add('shell')
+
+# Registered Targets
+import subprocess
+import re
+import os
+
+def getRegisteredTargets(tool):
+ set_of_targets = set()
+
+ cmd = subprocess.Popen([tool, '-version'], stdout=subprocess.PIPE)
+
+ # Parse the stdout to get the list of registered targets.
+ parse_targets = False
+ for line in cmd.stdout:
+ if parse_targets:
+ m = re.match( r'(.*) - ', line)
+ if m is not None:
+ set_of_targets.add(m.group(1).strip() + '-registered-target')
+ else:
+ break
+ elif "Registered Targets:" in line:
+ parse_targets = True
+
+ return set_of_targets
+
+registered_targets = getRegisteredTargets(os.path.join(llvm_tools_dir, 'llc'))
+if len(registered_targets) > 0:
+ config.available_features.update(registered_targets)
+else:
+ lit.fatal('No Targets Registered with the LLVM Tools!')
diff --git a/tools/c-index-test/c-index-test.c b/tools/c-index-test/c-index-test.c
index f7b7a36..837fc89 100644
--- a/tools/c-index-test/c-index-test.c
+++ b/tools/c-index-test/c-index-test.c
@@ -37,6 +37,8 @@ static unsigned getDefaultParsingOptions() {
options |= clang_defaultEditingTranslationUnitOptions();
if (getenv("CINDEXTEST_COMPLETION_CACHING"))
options |= CXTranslationUnit_CacheCompletionResults;
+ if (getenv("CINDEXTEST_NESTED_MACROS"))
+ options |= CXTranslationUnit_NestedMacroInstantiations;
return options;
}
@@ -158,7 +160,7 @@ int parse_remapped_files(int argc, const char **argv, int start_arg,
int want_display_name = 0;
-static void PrintCursor(CXCursor Cursor) {
+static void PrintCursor(CXTranslationUnit TU, CXCursor Cursor) {
if (clang_isInvalid(Cursor.kind)) {
CXString ks = clang_getCursorKindSpelling(Cursor.kind);
printf("Invalid Cursor => %s", clang_getCString(ks));
@@ -219,6 +221,11 @@ static void PrintCursor(CXCursor Cursor) {
break;
}
+ if (clang_CXXMethod_isStatic(Cursor))
+ printf(" (static)");
+ if (clang_CXXMethod_isVirtual(Cursor))
+ printf(" (virtual)");
+
if (Cursor.kind == CXCursor_IBOutletCollectionAttr) {
CXType T =
clang_getCanonicalType(clang_getIBOutletCollectionType(Cursor));
@@ -277,6 +284,9 @@ static void PrintCursor(CXCursor Cursor) {
CXString Included = clang_getFileName(File);
printf(" (%s)", clang_getCString(Included));
clang_disposeString(Included);
+
+ if (clang_isFileMultipleIncludeGuarded(TU, File))
+ printf(" [multi-include guarded]");
}
}
}
@@ -426,7 +436,7 @@ enum CXChildVisitResult FilteredPrintingVisitor(CXCursor Cursor,
clang_getSpellingLocation(Loc, 0, &line, &column, 0);
printf("// %s: %s:%d:%d: ", FileCheckPrefix,
GetCursorSource(Cursor), line, column);
- PrintCursor(Cursor);
+ PrintCursor(Data->TU, Cursor);
PrintCursorExtent(Cursor);
printf("\n");
return CXChildVisit_Recurse;
@@ -479,7 +489,7 @@ static enum CXChildVisitResult FunctionScanVisitor(CXCursor Cursor,
} else if (Ref.kind != CXCursor_FunctionDecl) {
printf("// %s: %s:%d:%d: ", FileCheckPrefix, GetCursorSource(Ref),
curLine, curColumn);
- PrintCursor(Ref);
+ PrintCursor(Data->TU, Ref);
printf("\n");
}
}
@@ -554,6 +564,8 @@ static enum CXChildVisitResult PrintLinkage(CXCursor cursor, CXCursor p,
CXClientData d) {
const char *linkage = 0;
+ VisitorData *Data = (VisitorData *)d;
+
if (clang_isInvalid(clang_getCursorKind(cursor)))
return CXChildVisit_Recurse;
@@ -566,7 +578,7 @@ static enum CXChildVisitResult PrintLinkage(CXCursor cursor, CXCursor p,
}
if (linkage) {
- PrintCursor(cursor);
+ PrintCursor(Data->TU, cursor);
printf("linkage=%s\n", linkage);
}
@@ -579,11 +591,12 @@ static enum CXChildVisitResult PrintLinkage(CXCursor cursor, CXCursor p,
static enum CXChildVisitResult PrintTypeKind(CXCursor cursor, CXCursor p,
CXClientData d) {
+ VisitorData *Data = (VisitorData *)d;
if (!clang_isInvalid(clang_getCursorKind(cursor))) {
CXType T = clang_getCursorType(cursor);
CXString S = clang_getTypeKindSpelling(T.kind);
- PrintCursor(cursor);
+ PrintCursor(Data->TU, cursor);
printf(" typekind=%s", clang_getCString(S));
if (clang_isConstQualifiedType(T))
printf(" const");
@@ -707,11 +720,11 @@ int perform_test_load_source(int argc, const char **argv,
return -1;
}
- TU = clang_createTranslationUnitFromSourceFile(Idx, 0,
- argc - num_unsaved_files,
- argv + num_unsaved_files,
- num_unsaved_files,
- unsaved_files);
+ TU = clang_parseTranslationUnit(Idx, 0,
+ argv + num_unsaved_files,
+ argc - num_unsaved_files,
+ unsaved_files, num_unsaved_files,
+ getDefaultParsingOptions());
if (!TU) {
fprintf(stderr, "Unable to load translation unit!\n");
free_remapped_files(unsaved_files, num_unsaved_files);
@@ -778,7 +791,7 @@ int perform_test_reparse_source(int argc, const char **argv, int trials,
/* Logic for testing clang_getCursor(). */
/******************************************************************************/
-static void print_cursor_file_scan(CXCursor cursor,
+static void print_cursor_file_scan(CXTranslationUnit TU, CXCursor cursor,
unsigned start_line, unsigned start_col,
unsigned end_line, unsigned end_col,
const char *prefix) {
@@ -787,7 +800,7 @@ static void print_cursor_file_scan(CXCursor cursor,
printf("-%s", prefix);
PrintExtent(stdout, start_line, start_col, end_line, end_col);
printf(" ");
- PrintCursor(cursor);
+ PrintCursor(TU, cursor);
printf("\n");
}
@@ -832,7 +845,7 @@ static int perform_file_scan(const char *ast_file, const char *source_file,
cursor = clang_getCursor(TU, clang_getLocation(TU, file, line, col));
if ((c == EOF || !clang_equalCursors(cursor, prevCursor)) &&
prevCursor.kind != CXCursor_InvalidFile) {
- print_cursor_file_scan(prevCursor, start_line, start_col,
+ print_cursor_file_scan(TU, prevCursor, start_line, start_col,
line, col, prefix);
start_line = line;
start_col = col;
@@ -1183,7 +1196,7 @@ int inspect_cursor_at(int argc, const char **argv) {
clang_getLocation(TU, file, Locations[Loc].line,
Locations[Loc].column));
if (I + 1 == Repeats) {
- PrintCursor(Cursor);
+ PrintCursor(TU, Cursor);
printf("\n");
free(Locations[Loc].filename);
}
@@ -1225,11 +1238,12 @@ int perform_token_annotation(int argc, const char **argv) {
return -1;
CIdx = clang_createIndex(0, 1);
- TU = clang_createTranslationUnitFromSourceFile(CIdx, argv[argc - 1],
- argc - num_unsaved_files - 3,
- argv + num_unsaved_files + 2,
- num_unsaved_files,
- unsaved_files);
+ TU = clang_parseTranslationUnit(CIdx, argv[argc - 1],
+ argv + num_unsaved_files + 2,
+ argc - num_unsaved_files - 3,
+ unsaved_files,
+ num_unsaved_files,
+ getDefaultParsingOptions());
if (!TU) {
fprintf(stderr, "unable to parse input\n");
clang_disposeIndex(CIdx);
@@ -1287,7 +1301,7 @@ int perform_token_annotation(int argc, const char **argv) {
PrintExtent(stdout, start_line, start_column, end_line, end_column);
if (!clang_isInvalid(cursors[i].kind)) {
printf(" ");
- PrintCursor(cursors[i]);
+ PrintCursor(TU, cursors[i]);
}
printf("\n");
}
diff --git a/tools/driver/cc1as_main.cpp b/tools/driver/cc1as_main.cpp
index ec6ce65..f449235 100644
--- a/tools/driver/cc1as_main.cpp
+++ b/tools/driver/cc1as_main.cpp
@@ -172,6 +172,8 @@ void AssemblerInvocation::CreateFromArgs(AssemblerInvocation &Opts,
}
}
Opts.LLVMArgs = Args->getAllArgValues(OPT_mllvm);
+ if (Args->hasArg(OPT_fatal_warnings))
+ Opts.LLVMArgs.push_back("-fatal-assembler-warnings");
Opts.OutputPath = Args->getLastArgValue(OPT_o);
if (Arg *A = Args->getLastArg(OPT_filetype)) {
StringRef Name = A->getValue(*Args);
diff --git a/tools/libclang/CIndex.cpp b/tools/libclang/CIndex.cpp
index 28f1506..2a9d96d 100644
--- a/tools/libclang/CIndex.cpp
+++ b/tools/libclang/CIndex.cpp
@@ -30,6 +30,7 @@
#include "clang/Frontend/CompilerInstance.h"
#include "clang/Frontend/FrontendDiagnostic.h"
#include "clang/Lex/Lexer.h"
+#include "clang/Lex/HeaderSearch.h"
#include "clang/Lex/PreprocessingRecord.h"
#include "clang/Lex/Preprocessor.h"
#include "llvm/ADT/STLExtras.h"
@@ -349,6 +350,7 @@ public:
bool VisitTypeOfExprTypeLoc(TypeOfExprTypeLoc TL);
bool VisitPackExpansionTypeLoc(PackExpansionTypeLoc TL);
bool VisitTypeOfTypeLoc(TypeOfTypeLoc TL);
+ bool VisitUnaryTransformTypeLoc(UnaryTransformTypeLoc TL);
bool VisitDependentNameTypeLoc(DependentNameTypeLoc TL);
bool VisitDependentTemplateSpecializationTypeLoc(
DependentTemplateSpecializationTypeLoc TL);
@@ -789,7 +791,7 @@ bool CursorVisitor::VisitFunctionDecl(FunctionDecl *ND) {
// FIXME: Attributes?
}
- if (ND->isThisDeclarationADefinition() && !ND->isLateTemplateParsed()) {
+ if (ND->doesThisDeclarationHaveABody() && !ND->isLateTemplateParsed()) {
if (CXXConstructorDecl *Constructor = dyn_cast<CXXConstructorDecl>(ND)) {
// Find the initializers that were written in the source.
llvm::SmallVector<CXXCtorInitializer *, 4> WrittenInits;
@@ -1552,6 +1554,13 @@ bool CursorVisitor::VisitTypeOfTypeLoc(TypeOfTypeLoc TL) {
return false;
}
+bool CursorVisitor::VisitUnaryTransformTypeLoc(UnaryTransformTypeLoc TL) {
+ if (TypeSourceInfo *TSInfo = TL.getUnderlyingTInfo())
+ return Visit(TSInfo->getTypeLoc());
+
+ return false;
+}
+
bool CursorVisitor::VisitDependentNameTypeLoc(DependentNameTypeLoc TL) {
if (VisitNestedNameSpecifierLoc(TL.getQualifierLoc()))
return true;
@@ -2375,10 +2384,12 @@ clang_createTranslationUnitFromSourceFile(CXIndex CIdx,
const char * const *command_line_args,
unsigned num_unsaved_files,
struct CXUnsavedFile *unsaved_files) {
+ unsigned Options = CXTranslationUnit_DetailedPreprocessingRecord |
+ CXTranslationUnit_NestedMacroInstantiations;
return clang_parseTranslationUnit(CIdx, source_filename,
command_line_args, num_command_line_args,
unsaved_files, num_unsaved_files,
- CXTranslationUnit_DetailedPreprocessingRecord);
+ Options);
}
struct ParseTranslationUnitInfo {
@@ -2479,9 +2490,12 @@ static void clang_parseTranslationUnit_Impl(void *UserData) {
Args->push_back(source_filename);
// Do we need the detailed preprocessing record?
+ bool NestedMacroInstantiations = false;
if (options & CXTranslationUnit_DetailedPreprocessingRecord) {
Args->push_back("-Xclang");
Args->push_back("-detailed-preprocessing-record");
+ NestedMacroInstantiations
+ = (options & CXTranslationUnit_NestedMacroInstantiations);
}
unsigned NumErrors = Diags->getClient()->getNumErrors();
@@ -2500,7 +2514,8 @@ static void clang_parseTranslationUnit_Impl(void *UserData) {
CompleteTranslationUnit,
CacheCodeCompetionResults,
CXXPrecompilePreamble,
- CXXChainedPCH));
+ CXXChainedPCH,
+ NestedMacroInstantiations));
if (NumErrors != Diags->getClient()->getNumErrors()) {
// Make sure to check that 'Unit' is non-NULL.
@@ -2559,8 +2574,10 @@ CXTranslationUnit clang_parseTranslationUnit(CXIndex CIdx,
fprintf(stderr, "}\n");
return 0;
+ } else if (getenv("LIBCLANG_RESOURCE_USAGE")) {
+ PrintLibclangResourceUsage(PTUI.result);
}
-
+
return PTUI.result;
}
@@ -2573,7 +2590,10 @@ int clang_saveTranslationUnit(CXTranslationUnit TU, const char *FileName,
if (!TU)
return 1;
- return static_cast<ASTUnit *>(TU->TUData)->Save(FileName);
+ int result = static_cast<ASTUnit *>(TU->TUData)->Save(FileName);
+ if (getenv("LIBCLANG_RESOURCE_USAGE"))
+ PrintLibclangResourceUsage(TU);
+ return result;
}
void clang_disposeTranslationUnit(CXTranslationUnit CTUnit) {
@@ -2649,8 +2669,8 @@ int clang_reparseTranslationUnit(CXTranslationUnit TU,
fprintf(stderr, "libclang: crash detected during reparsing\n");
static_cast<ASTUnit *>(TU->TUData)->setUnsafeToFree(true);
return 1;
- }
-
+ } else if (getenv("LIBCLANG_RESOURCE_USAGE"))
+ PrintLibclangResourceUsage(TU);
return RTUI.result;
}
@@ -2807,17 +2827,8 @@ void clang_getSpellingLocation(CXSourceLocation location,
unsigned *offset) {
SourceLocation Loc = SourceLocation::getFromRawEncoding(location.int_data);
- if (!location.ptr_data[0] || Loc.isInvalid()) {
- if (file)
- *file = 0;
- if (line)
- *line = 0;
- if (column)
- *column = 0;
- if (offset)
- *offset = 0;
- return;
- }
+ if (!location.ptr_data[0] || Loc.isInvalid())
+ return createNullLocation(file, line, column, offset);
const SourceManager &SM =
*static_cast<const SourceManager*>(location.ptr_data[0]);
@@ -2835,6 +2846,9 @@ void clang_getSpellingLocation(CXSourceLocation location,
FileID FID = LocInfo.first;
unsigned FileOffset = LocInfo.second;
+ if (FID.isInvalid())
+ return createNullLocation(file, line, column, offset);
+
if (file)
*file = (void *)SM.getFileEntryForID(FID);
if (line)
@@ -2890,6 +2904,16 @@ CXFile clang_getFile(CXTranslationUnit tu, const char *file_name) {
return const_cast<FileEntry *>(FMgr.getFile(file_name));
}
+unsigned clang_isFileMultipleIncludeGuarded(CXTranslationUnit tu, CXFile file) {
+ if (!tu || !file)
+ return 0;
+
+ ASTUnit *CXXUnit = static_cast<ASTUnit *>(tu->TUData);
+ FileEntry *FEnt = static_cast<FileEntry *>(file);
+ return CXXUnit->getPreprocessor().getHeaderSearchInfo()
+ .isFileMultipleIncludeGuarded(FEnt);
+}
+
} // end: extern "C"
//===----------------------------------------------------------------------===//
@@ -3357,7 +3381,11 @@ CXString clang_getCursorKindSpelling(enum CXCursorKind Kind) {
case CXCursor_UsingDeclaration:
return createCXString("UsingDeclaration");
case CXCursor_TypeAliasDecl:
- return createCXString("TypeAliasDecl");
+ return createCXString("TypeAliasDecl");
+ case CXCursor_ObjCSynthesizeDecl:
+ return createCXString("ObjCSynthesizeDecl");
+ case CXCursor_ObjCDynamicDecl:
+ return createCXString("ObjCDynamicDecl");
}
llvm_unreachable("Unhandled CXCursorKind");
@@ -3899,6 +3927,7 @@ CXCursor clang_getCursorDefinition(CXCursor C) {
case Decl::Namespace:
case Decl::Typedef:
case Decl::TypeAlias:
+ case Decl::TypeAliasTemplate:
case Decl::TemplateTypeParm:
case Decl::EnumConstant:
case Decl::Field:
@@ -5169,6 +5198,19 @@ unsigned clang_CXXMethod_isStatic(CXCursor C) {
return (Method && Method->isStatic()) ? 1 : 0;
}
+unsigned clang_CXXMethod_isVirtual(CXCursor C) {
+ if (!clang_isDeclaration(C.kind))
+ return 0;
+
+ CXXMethodDecl *Method = 0;
+ Decl *D = cxcursor::getCursorDecl(C);
+ if (FunctionTemplateDecl *FunTmpl = dyn_cast_or_null<FunctionTemplateDecl>(D))
+ Method = dyn_cast<CXXMethodDecl>(FunTmpl->getTemplatedDecl());
+ else
+ Method = dyn_cast_or_null<CXXMethodDecl>(D);
+ return (Method && Method->isVirtual()) ? 1 : 0;
+}
+
} // end: extern "C"
//===----------------------------------------------------------------------===//
@@ -5235,6 +5277,12 @@ const char *clang_getTUResourceUsageName(CXTUResourceUsageKind kind) {
case CXTUResourceUsage_ExternalASTSource_Membuffer_MMap:
str = "ExternalASTSource: mmap'ed memory buffers";
break;
+ case CXTUResourceUsage_Preprocessor:
+ str = "Preprocessor: malloc'ed memory";
+ break;
+ case CXTUResourceUsage_PreprocessingRecord:
+ str = "Preprocessor: PreprocessingRecord";
+ break;
}
return str;
}
@@ -5269,7 +5317,7 @@ CXTUResourceUsage clang_getCXTUResourceUsage(CXTranslationUnit TU) {
unsigned long completionBytes = 0;
if (GlobalCodeCompletionAllocator *completionAllocator =
astUnit->getCachedCompletionAllocator().getPtr()) {
- completionBytes = completionAllocator-> getTotalMemory();
+ completionBytes = completionAllocator->getTotalMemory();
}
createCXTUResourceUsageEntry(*entries,
CXTUResourceUsage_GlobalCompletionResults,
@@ -5303,7 +5351,21 @@ CXTUResourceUsage clang_getCXTUResourceUsage(CXTranslationUnit TU) {
CXTUResourceUsage_ExternalASTSource_Membuffer_MMap,
(unsigned long) sizes.mmap_bytes);
}
-
+
+ // How much memory is being used by the Preprocessor?
+ Preprocessor &pp = astUnit->getPreprocessor();
+ const llvm::BumpPtrAllocator &ppAlloc = pp.getPreprocessorAllocator();
+ createCXTUResourceUsageEntry(*entries,
+ CXTUResourceUsage_Preprocessor,
+ ppAlloc.getTotalMemory());
+
+ if (PreprocessingRecord *pRec = pp.getPreprocessingRecord()) {
+ createCXTUResourceUsageEntry(*entries,
+ CXTUResourceUsage_PreprocessingRecord,
+ pRec->getTotalMemory());
+ }
+
+
CXTUResourceUsage usage = { (void*) entries.get(),
(unsigned) entries->size(),
entries->size() ? &(*entries)[0] : 0 };
@@ -5318,6 +5380,16 @@ void clang_disposeCXTUResourceUsage(CXTUResourceUsage usage) {
} // end extern "C"
+void clang::PrintLibclangResourceUsage(CXTranslationUnit TU) {
+ CXTUResourceUsage Usage = clang_getCXTUResourceUsage(TU);
+ for (unsigned I = 0; I != Usage.numEntries; ++I)
+ fprintf(stderr, " %s: %lu\n",
+ clang_getTUResourceUsageName(Usage.entries[I].kind),
+ Usage.entries[I].amount);
+
+ clang_disposeCXTUResourceUsage(Usage);
+}
+
//===----------------------------------------------------------------------===//
// Misc. utility functions.
//===----------------------------------------------------------------------===//
diff --git a/tools/libclang/CIndexCodeCompletion.cpp b/tools/libclang/CIndexCodeCompletion.cpp
index e85e802..0c8317e 100644
--- a/tools/libclang/CIndexCodeCompletion.cpp
+++ b/tools/libclang/CIndexCodeCompletion.cpp
@@ -498,7 +498,8 @@ CXCodeCompleteResults *clang_codeCompleteAt(CXTranslationUnit TU,
fprintf(stderr, "libclang: crash detected in code completion\n");
static_cast<ASTUnit *>(TU->TUData)->setUnsafeToFree(true);
return 0;
- }
+ } else if (getenv("LIBCLANG_RESOURCE_USAGE"))
+ PrintLibclangResourceUsage(TU);
return CCAI.result;
}
diff --git a/tools/libclang/CIndexDiagnostic.cpp b/tools/libclang/CIndexDiagnostic.cpp
index fa3b1ce..0fcdab7 100644
--- a/tools/libclang/CIndexDiagnostic.cpp
+++ b/tools/libclang/CIndexDiagnostic.cpp
@@ -220,7 +220,8 @@ CXString clang_getDiagnosticOption(CXDiagnostic Diag, CXString *Disable) {
return createCXString("");
unsigned ID = StoredDiag->Diag.getID();
- if (const char *Option = DiagnosticIDs::getWarningOptionForDiag(ID)) {
+ llvm::StringRef Option = DiagnosticIDs::getWarningOptionForDiag(ID);
+ if (!Option.empty()) {
if (Disable)
*Disable = createCXString((llvm::Twine("-Wno-") + Option).str());
return createCXString((llvm::Twine("-W") + Option).str());
diff --git a/tools/libclang/CIndexUSRs.cpp b/tools/libclang/CIndexUSRs.cpp
index 9917d2a..4f1f071 100644
--- a/tools/libclang/CIndexUSRs.cpp
+++ b/tools/libclang/CIndexUSRs.cpp
@@ -477,6 +477,9 @@ bool USRGenerator::GenLoc(const Decl *D) {
return true;
}
+ // Use the location of canonical decl.
+ D = D->getCanonicalDecl();
+
const SourceManager &SM = AU->getSourceManager();
SourceLocation L = D->getLocStart();
if (L.isInvalid()) {
diff --git a/tools/libclang/CIndexer.h b/tools/libclang/CIndexer.h
index b40891a..45d0831 100644
--- a/tools/libclang/CIndexer.h
+++ b/tools/libclang/CIndexer.h
@@ -77,6 +77,9 @@ namespace clang {
/// \return False if a crash was detected.
bool RunSafely(llvm::CrashRecoveryContext &CRC,
void (*Fn)(void*), void *UserData, unsigned Size = 0);
+
+ /// \brief Print libclang's resource usage to standard error.
+ void PrintLibclangResourceUsage(CXTranslationUnit TU);
}
#endif
diff --git a/tools/libclang/CXCursor.cpp b/tools/libclang/CXCursor.cpp
index 2a78012..b34370d 100644
--- a/tools/libclang/CXCursor.cpp
+++ b/tools/libclang/CXCursor.cpp
@@ -173,6 +173,7 @@ CXCursor cxcursor::MakeCXCursor(Stmt *S, Decl *Parent,
case Stmt::OpaqueValueExprClass:
case Stmt::PackExpansionExprClass:
case Stmt::SizeOfPackExprClass:
+ case Stmt::AsTypeExprClass:
K = CXCursor_UnexposedExpr;
break;
diff --git a/tools/libclang/CXType.cpp b/tools/libclang/CXType.cpp
index 9332672..5af9553 100644
--- a/tools/libclang/CXType.cpp
+++ b/tools/libclang/CXType.cpp
@@ -379,9 +379,10 @@ CXString clang_getDeclObjCTypeEncoding(CXCursor C) {
ASTContext &Ctx = AU->getASTContext();
std::string encoding;
- if (ObjCMethodDecl *OMD = dyn_cast<ObjCMethodDecl>(D))
- Ctx.getObjCEncodingForMethodDecl(OMD, encoding);
- else if (ObjCPropertyDecl *OPD = dyn_cast<ObjCPropertyDecl>(D))
+ if (ObjCMethodDecl *OMD = dyn_cast<ObjCMethodDecl>(D)) {
+ if (Ctx.getObjCEncodingForMethodDecl(OMD, encoding))
+ return cxstring::createCXString("?");
+ } else if (ObjCPropertyDecl *OPD = dyn_cast<ObjCPropertyDecl>(D))
Ctx.getObjCEncodingForPropertyDecl(OPD, NULL, encoding);
else if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D))
Ctx.getObjCEncodingForFunctionDecl(FD, encoding);
diff --git a/tools/libclang/libclang.darwin.exports b/tools/libclang/libclang.darwin.exports
index 30c3fd1..85dfcb6 100644
--- a/tools/libclang/libclang.darwin.exports
+++ b/tools/libclang/libclang.darwin.exports
@@ -1,6 +1,7 @@
_clang_CXCursorSet_contains
_clang_CXCursorSet_insert
_clang_CXXMethod_isStatic
+_clang_CXXMethod_isVirtual
_clang_annotateTokens
_clang_codeCompleteAt
_clang_codeCompleteGetDiagnostic
@@ -115,6 +116,7 @@ _clang_isConstQualifiedType
_clang_isCursorDefinition
_clang_isDeclaration
_clang_isExpression
+_clang_isFileMultipleIncludeGuarded
_clang_isInvalid
_clang_isPODType
_clang_isPreprocessing
diff --git a/tools/libclang/libclang.exports b/tools/libclang/libclang.exports
index 4e96e8a..403cd67 100644
--- a/tools/libclang/libclang.exports
+++ b/tools/libclang/libclang.exports
@@ -1,6 +1,7 @@
clang_CXCursorSet_contains
clang_CXCursorSet_insert
clang_CXXMethod_isStatic
+clang_CXXMethod_isVirtual
clang_annotateTokens
clang_codeCompleteAt
clang_codeCompleteGetDiagnostic
@@ -115,6 +116,7 @@ clang_isConstQualifiedType
clang_isCursorDefinition
clang_isDeclaration
clang_isExpression
+clang_isFileMultipleIncludeGuarded
clang_isInvalid
clang_isPODType
clang_isPreprocessing
diff --git a/unittests/CMakeLists.txt b/unittests/CMakeLists.txt
index f7f495e..cb44dc5 100644
--- a/unittests/CMakeLists.txt
+++ b/unittests/CMakeLists.txt
@@ -36,7 +36,7 @@ set_target_properties(ClangUnitTests PROPERTIES FOLDER "Clang tests")
include_directories(${LLVM_MAIN_SRC_DIR}/utils/unittest/googletest/include)
add_definitions(-DGTEST_HAS_RTTI=0)
-if( CMAKE_COMPILER_IS_GNUCXX )
+if( LLVM_COMPILER_IS_GCC_COMPATIBLE )
llvm_replace_compiler_option(CMAKE_CXX_FLAGS "-frtti" "-fno-rtti")
elseif( MSVC )
llvm_replace_compiler_option(CMAKE_CXX_FLAGS "/GR" "/GR-")
@@ -59,13 +59,3 @@ add_clang_unittest(Frontend
Frontend/FrontendActionTest.cpp
USED_LIBS gtest gtest_main clangFrontend
)
-
-add_clang_unittest(Tooling
- Tooling/ToolingTest.cpp
- USED_LIBS gtest gtest_main clangTooling
- )
-
-add_clang_unittest(JsonCompileCommandLineDatabase
- Tooling/JsonCompileCommandLineDatabaseTest.cpp
- USED_LIBS gtest gtest_main clangTooling
- )
diff --git a/unittests/Tooling/JsonCompileCommandLineDatabaseTest.cpp b/unittests/Tooling/JsonCompileCommandLineDatabaseTest.cpp
deleted file mode 100644
index d875293..0000000
--- a/unittests/Tooling/JsonCompileCommandLineDatabaseTest.cpp
+++ /dev/null
@@ -1,232 +0,0 @@
-//===- unittest/Tooling/JsonCompileCommandLineDatabaseTest ----------------===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-
-#include "../../lib/Tooling/JsonCompileCommandLineDatabase.h"
-#include "gtest/gtest.h"
-
-namespace clang {
-namespace tooling {
-
-TEST(UnescapeJsonCommandLine, ReturnsEmptyArrayOnEmptyString) {
- std::vector<std::string> Result = UnescapeJsonCommandLine("");
- EXPECT_TRUE(Result.empty());
-}
-
-TEST(UnescapeJsonCommandLine, SplitsOnSpaces) {
- std::vector<std::string> Result = UnescapeJsonCommandLine("a b c");
- ASSERT_EQ(3ul, Result.size());
- EXPECT_EQ("a", Result[0]);
- EXPECT_EQ("b", Result[1]);
- EXPECT_EQ("c", Result[2]);
-}
-
-TEST(UnescapeJsonCommandLine, MungesMultipleSpaces) {
- std::vector<std::string> Result = UnescapeJsonCommandLine(" a b ");
- ASSERT_EQ(2ul, Result.size());
- EXPECT_EQ("a", Result[0]);
- EXPECT_EQ("b", Result[1]);
-}
-
-TEST(UnescapeJsonCommandLine, UnescapesBackslashCharacters) {
- std::vector<std::string> Backslash = UnescapeJsonCommandLine("a\\\\\\\\");
- ASSERT_EQ(1ul, Backslash.size());
- EXPECT_EQ("a\\", Backslash[0]);
- std::vector<std::string> Quote = UnescapeJsonCommandLine("a\\\\\\\"");
- ASSERT_EQ(1ul, Quote.size());
- EXPECT_EQ("a\"", Quote[0]);
-}
-
-TEST(UnescapeJsonCommandLine, DoesNotMungeSpacesBetweenQuotes) {
- std::vector<std::string> Result = UnescapeJsonCommandLine("\\\" a b \\\"");
- ASSERT_EQ(1ul, Result.size());
- EXPECT_EQ(" a b ", Result[0]);
-}
-
-TEST(UnescapeJsonCommandLine, AllowsMultipleQuotedArguments) {
- std::vector<std::string> Result = UnescapeJsonCommandLine(
- " \\\" a \\\" \\\" b \\\" ");
- ASSERT_EQ(2ul, Result.size());
- EXPECT_EQ(" a ", Result[0]);
- EXPECT_EQ(" b ", Result[1]);
-}
-
-TEST(UnescapeJsonCommandLine, AllowsEmptyArgumentsInQuotes) {
- std::vector<std::string> Result = UnescapeJsonCommandLine(
- "\\\"\\\"\\\"\\\"");
- ASSERT_EQ(1ul, Result.size());
- EXPECT_TRUE(Result[0].empty()) << Result[0];
-}
-
-TEST(UnescapeJsonCommandLine, ParsesEscapedQuotesInQuotedStrings) {
- std::vector<std::string> Result = UnescapeJsonCommandLine(
- "\\\"\\\\\\\"\\\"");
- ASSERT_EQ(1ul, Result.size());
- EXPECT_EQ("\"", Result[0]);
-}
-
-TEST(UnescapeJsonCommandLine, ParsesMultipleArgumentsWithEscapedCharacters) {
- std::vector<std::string> Result = UnescapeJsonCommandLine(
- " \\\\\\\" \\\"a \\\\\\\" b \\\" \\\"and\\\\\\\\c\\\" \\\\\\\"");
- ASSERT_EQ(4ul, Result.size());
- EXPECT_EQ("\"", Result[0]);
- EXPECT_EQ("a \" b ", Result[1]);
- EXPECT_EQ("and\\c", Result[2]);
- EXPECT_EQ("\"", Result[3]);
-}
-
-TEST(UnescapeJsonCommandLine, ParsesStringsWithoutSpacesIntoSingleArgument) {
- std::vector<std::string> QuotedNoSpaces = UnescapeJsonCommandLine(
- "\\\"a\\\"\\\"b\\\"");
- ASSERT_EQ(1ul, QuotedNoSpaces.size());
- EXPECT_EQ("ab", QuotedNoSpaces[0]);
-
- std::vector<std::string> MixedNoSpaces = UnescapeJsonCommandLine(
- "\\\"a\\\"bcd\\\"ef\\\"\\\"\\\"\\\"g\\\"");
- ASSERT_EQ(1ul, MixedNoSpaces.size());
- EXPECT_EQ("abcdefg", MixedNoSpaces[0]);
-}
-
-TEST(JsonCompileCommandLineParser, FailsOnEmptyString) {
- JsonCompileCommandLineParser Parser("", NULL);
- EXPECT_FALSE(Parser.Parse()) << Parser.GetErrorMessage();
-}
-
-TEST(JsonCompileCommandLineParser, DoesNotReadAfterInput) {
- JsonCompileCommandLineParser Parser(llvm::StringRef(NULL, 0), NULL);
- EXPECT_FALSE(Parser.Parse()) << Parser.GetErrorMessage();
-}
-
-TEST(JsonCompileCommandLineParser, ParsesEmptyArray) {
- JsonCompileCommandLineParser Parser("[]", NULL);
- EXPECT_TRUE(Parser.Parse()) << Parser.GetErrorMessage();
-}
-
-TEST(JsonCompileCommandLineParser, FailsIfNotClosingArray) {
- JsonCompileCommandLineParser JustOpening("[", NULL);
- EXPECT_FALSE(JustOpening.Parse()) << JustOpening.GetErrorMessage();
- JsonCompileCommandLineParser WithSpaces(" [ ", NULL);
- EXPECT_FALSE(WithSpaces.Parse()) << WithSpaces.GetErrorMessage();
- JsonCompileCommandLineParser WithGarbage(" [x", NULL);
- EXPECT_FALSE(WithGarbage.Parse()) << WithGarbage.GetErrorMessage();
-}
-
-TEST(JsonCompileCommandLineParser, ParsesEmptyArrayWithWhitespace) {
- JsonCompileCommandLineParser Spaces(" [ ] ", NULL);
- EXPECT_TRUE(Spaces.Parse()) << Spaces.GetErrorMessage();
- JsonCompileCommandLineParser AllWhites("\t\r\n[\t\n \t\r ]\t\r \n\n", NULL);
- EXPECT_TRUE(AllWhites.Parse()) << AllWhites.GetErrorMessage();
-}
-
-TEST(JsonCompileCommandLineParser, FailsIfNotStartingArray) {
- JsonCompileCommandLineParser ObjectStart("{", NULL);
- EXPECT_FALSE(ObjectStart.Parse()) << ObjectStart.GetErrorMessage();
- // We don't implement a full JSON parser, and thus parse only a subset
- // of valid JSON.
- JsonCompileCommandLineParser Object("{}", NULL);
- EXPECT_FALSE(Object.Parse()) << Object.GetErrorMessage();
- JsonCompileCommandLineParser Character("x", NULL);
- EXPECT_FALSE(Character.Parse()) << Character.GetErrorMessage();
-}
-
-TEST(JsonCompileCommandLineParser, ParsesEmptyObject) {
- JsonCompileCommandLineParser Parser("[{}]", NULL);
- EXPECT_TRUE(Parser.Parse()) << Parser.GetErrorMessage();
-}
-
-TEST(JsonCompileCommandLineParser, ParsesObject) {
- JsonCompileCommandLineParser Parser("[{\"a\":\"/b\"}]", NULL);
- EXPECT_TRUE(Parser.Parse()) << Parser.GetErrorMessage();
-}
-
-TEST(JsonCompileCommandLineParser, ParsesMultipleKeyValuePairsInObject) {
- JsonCompileCommandLineParser Parser(
- "[{\"a\":\"/b\",\"c\":\"d\",\"e\":\"f\"}]", NULL);
- EXPECT_TRUE(Parser.Parse()) << Parser.GetErrorMessage();
-}
-
-TEST(JsonCompileCommandLineParser, FailsIfNotClosingObject) {
- JsonCompileCommandLineParser MissingCloseOnEmpty("[{]", NULL);
- EXPECT_FALSE(MissingCloseOnEmpty.Parse())
- << MissingCloseOnEmpty.GetErrorMessage();
- JsonCompileCommandLineParser MissingCloseAfterPair("[{\"a\":\"b\"]", NULL);
- EXPECT_FALSE(MissingCloseAfterPair.Parse())
- << MissingCloseAfterPair.GetErrorMessage();
-}
-
-TEST(JsonCompileCommandLineParser, FailsIfMissingColon) {
- JsonCompileCommandLineParser StringString("[{\"a\"\"/b\"}]", NULL);
- EXPECT_FALSE(StringString.Parse()) << StringString.GetErrorMessage();
- JsonCompileCommandLineParser StringSpaceString("[{\"a\" \"b\"}]", NULL);
- EXPECT_FALSE(StringSpaceString.Parse())
- << StringSpaceString.GetErrorMessage();
-}
-
-TEST(JsonCompileCommandLineParser, FailsOnMissingQuote) {
- JsonCompileCommandLineParser OpenQuote("[{a\":\"b\"}]", NULL);
- EXPECT_FALSE(OpenQuote.Parse()) << OpenQuote.GetErrorMessage();
- JsonCompileCommandLineParser CloseQuote("[{\"a\":\"b}]", NULL);
- EXPECT_FALSE(CloseQuote.Parse()) << CloseQuote.GetErrorMessage();
-}
-
-TEST(JsonCompileCommandLineParser, ParsesEscapedQuotes) {
- JsonCompileCommandLineParser Parser(
- "[{\"a\":\"\\\"b\\\" \\\" \\\"\"}]", NULL);
- EXPECT_TRUE(Parser.Parse()) << Parser.GetErrorMessage();
-}
-
-TEST(JsonCompileCommandLineParser, ParsesEmptyString) {
- JsonCompileCommandLineParser Parser("[{\"a\":\"\"}]", NULL);
- EXPECT_TRUE(Parser.Parse()) << Parser.GetErrorMessage();
-}
-
-TEST(JsonCompileCommandLineParser, FailsOnMissingString) {
- JsonCompileCommandLineParser MissingValue("[{\"a\":}]", NULL);
- EXPECT_FALSE(MissingValue.Parse()) << MissingValue.GetErrorMessage();
- JsonCompileCommandLineParser MissingKey("[{:\"b\"}]", NULL);
- EXPECT_FALSE(MissingKey.Parse()) << MissingKey.GetErrorMessage();
-}
-
-TEST(JsonCompileCommandLineParser, ParsesMultipleObjects) {
- JsonCompileCommandLineParser Parser(
- "["
- " { \"a\" : \"b\" },"
- " { \"a\" : \"b\" },"
- " { \"a\" : \"b\" }"
- "]", NULL);
- EXPECT_TRUE(Parser.Parse()) << Parser.GetErrorMessage();
-}
-
-TEST(JsonCompileCommandLineParser, FailsOnMissingComma) {
- JsonCompileCommandLineParser Parser(
- "["
- " { \"a\" : \"b\" }"
- " { \"a\" : \"b\" }"
- "]", NULL);
- EXPECT_FALSE(Parser.Parse()) << Parser.GetErrorMessage();
-}
-
-TEST(JsonCompileCommandLineParser, FailsOnSuperfluousComma) {
- JsonCompileCommandLineParser Parser(
- "[ { \"a\" : \"b\" }, ]", NULL);
- EXPECT_FALSE(Parser.Parse()) << Parser.GetErrorMessage();
-}
-
-TEST(JsonCompileCommandLineParser, ParsesSpacesInBetweenTokens) {
- JsonCompileCommandLineParser Parser(
- " \t \n\n \r [ \t \n\n \r"
- " \t \n\n \r { \t \n\n \r\"a\"\t \n\n \r :"
- " \t \n\n \r \"b\"\t \n\n \r } \t \n\n \r,\t \n\n \r"
- " \t \n\n \r { \t \n\n \r\"a\"\t \n\n \r :"
- " \t \n\n \r \"b\"\t \n\n \r } \t \n\n \r]\t \n\n \r",
- NULL);
- EXPECT_TRUE(Parser.Parse()) << Parser.GetErrorMessage();
-}
-
-} // end namespace tooling
-} // end namespace clang
diff --git a/unittests/Tooling/ToolingTest.cpp b/unittests/Tooling/ToolingTest.cpp
deleted file mode 100644
index 6e5bc6b..0000000
--- a/unittests/Tooling/ToolingTest.cpp
+++ /dev/null
@@ -1,175 +0,0 @@
-//===- unittest/Tooling/ToolingTest.cpp - Tooling unit tests --------------===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-
-#include "llvm/ADT/Twine.h"
-#include "clang/AST/ASTConsumer.h"
-#include "clang/AST/DeclCXX.h"
-#include "clang/AST/DeclGroup.h"
-#include "clang/Frontend/FrontendAction.h"
-#include "clang/Tooling/Tooling.h"
-#include "gtest/gtest.h"
-
-namespace clang {
-namespace tooling {
-
-namespace {
-/// Takes an ast consumer and returns it from CreateASTConsumer. This only
-/// works with single translation unit compilations.
-class TestAction : public clang::ASTFrontendAction {
- public:
- /// Takes ownership of TestConsumer.
- explicit TestAction(clang::ASTConsumer *TestConsumer)
- : TestConsumer(TestConsumer) {}
-
- protected:
- virtual clang::ASTConsumer* CreateASTConsumer(
- clang::CompilerInstance& compiler, llvm::StringRef dummy) {
- /// TestConsumer will be deleted by the framework calling us.
- return TestConsumer;
- }
-
- private:
- clang::ASTConsumer * const TestConsumer;
-};
-
-class FindTopLevelDeclConsumer : public clang::ASTConsumer {
- public:
- explicit FindTopLevelDeclConsumer(bool *FoundTopLevelDecl)
- : FoundTopLevelDecl(FoundTopLevelDecl) {}
- virtual void HandleTopLevelDecl(clang::DeclGroupRef DeclGroup) {
- *FoundTopLevelDecl = true;
- }
- private:
- bool * const FoundTopLevelDecl;
-};
-} // end namespace
-
-TEST(RunSyntaxOnlyToolOnCode, FindsTopLevelDeclOnEmptyCode) {
- bool FoundTopLevelDecl = false;
- EXPECT_TRUE(RunSyntaxOnlyToolOnCode(
- new TestAction(new FindTopLevelDeclConsumer(&FoundTopLevelDecl)), ""));
- EXPECT_TRUE(FoundTopLevelDecl);
-}
-
-namespace {
-class FindClassDeclXConsumer : public clang::ASTConsumer {
- public:
- FindClassDeclXConsumer(bool *FoundClassDeclX)
- : FoundClassDeclX(FoundClassDeclX) {}
- virtual void HandleTopLevelDecl(clang::DeclGroupRef GroupRef) {
- if (CXXRecordDecl* Record = llvm::dyn_cast<clang::CXXRecordDecl>(
- *GroupRef.begin())) {
- if (Record->getName() == "X") {
- *FoundClassDeclX = true;
- }
- }
- }
- private:
- bool *FoundClassDeclX;
-};
-} // end namespace
-
-TEST(RunSyntaxOnlyToolOnCode, FindsClassDecl) {
- bool FoundClassDeclX = false;
- EXPECT_TRUE(RunSyntaxOnlyToolOnCode(new TestAction(
- new FindClassDeclXConsumer(&FoundClassDeclX)), "class X;"));
- EXPECT_TRUE(FoundClassDeclX);
-
- FoundClassDeclX = false;
- EXPECT_TRUE(RunSyntaxOnlyToolOnCode(new TestAction(
- new FindClassDeclXConsumer(&FoundClassDeclX)), "class Y;"));
- EXPECT_FALSE(FoundClassDeclX);
-}
-
-TEST(FindCompileArgsInJsonDatabase, FindsNothingIfEmpty) {
- std::string ErrorMessage;
- CompileCommand NotFound = FindCompileArgsInJsonDatabase(
- "a-file.cpp", "", ErrorMessage);
- EXPECT_TRUE(NotFound.CommandLine.empty()) << ErrorMessage;
- EXPECT_TRUE(NotFound.Directory.empty()) << ErrorMessage;
-}
-
-TEST(FindCompileArgsInJsonDatabase, ReadsSingleEntry) {
- llvm::StringRef Directory("/some/directory");
- llvm::StringRef FileName("/path/to/a-file.cpp");
- llvm::StringRef Command("/path/to/compiler and some arguments");
- std::string ErrorMessage;
- CompileCommand FoundCommand = FindCompileArgsInJsonDatabase(
- FileName,
- (llvm::Twine("[{\"directory\":\"") + Directory + "\"," +
- "\"command\":\"" + Command + "\","
- "\"file\":\"" + FileName + "\"}]").str(), ErrorMessage);
- EXPECT_EQ(Directory, FoundCommand.Directory) << ErrorMessage;
- ASSERT_EQ(4u, FoundCommand.CommandLine.size()) << ErrorMessage;
- EXPECT_EQ("/path/to/compiler", FoundCommand.CommandLine[0]) << ErrorMessage;
- EXPECT_EQ("and", FoundCommand.CommandLine[1]) << ErrorMessage;
- EXPECT_EQ("some", FoundCommand.CommandLine[2]) << ErrorMessage;
- EXPECT_EQ("arguments", FoundCommand.CommandLine[3]) << ErrorMessage;
-
- CompileCommand NotFound = FindCompileArgsInJsonDatabase(
- "a-file.cpp",
- (llvm::Twine("[{\"directory\":\"") + Directory + "\"," +
- "\"command\":\"" + Command + "\","
- "\"file\":\"" + FileName + "\"}]").str(), ErrorMessage);
- EXPECT_TRUE(NotFound.Directory.empty()) << ErrorMessage;
- EXPECT_TRUE(NotFound.CommandLine.empty()) << ErrorMessage;
-}
-
-TEST(FindCompileArgsInJsonDatabase, ReadsCompileCommandLinesWithSpaces) {
- llvm::StringRef Directory("/some/directory");
- llvm::StringRef FileName("/path/to/a-file.cpp");
- llvm::StringRef Command("\\\"/path to compiler\\\" \\\"and an argument\\\"");
- std::string ErrorMessage;
- CompileCommand FoundCommand = FindCompileArgsInJsonDatabase(
- FileName,
- (llvm::Twine("[{\"directory\":\"") + Directory + "\"," +
- "\"command\":\"" + Command + "\","
- "\"file\":\"" + FileName + "\"}]").str(), ErrorMessage);
- ASSERT_EQ(2u, FoundCommand.CommandLine.size());
- EXPECT_EQ("/path to compiler", FoundCommand.CommandLine[0]) << ErrorMessage;
- EXPECT_EQ("and an argument", FoundCommand.CommandLine[1]) << ErrorMessage;
-}
-
-TEST(FindCompileArgsInJsonDatabase, ReadsDirectoryWithSpaces) {
- llvm::StringRef Directory("/some directory / with spaces");
- llvm::StringRef FileName("/path/to/a-file.cpp");
- llvm::StringRef Command("a command");
- std::string ErrorMessage;
- CompileCommand FoundCommand = FindCompileArgsInJsonDatabase(
- FileName,
- (llvm::Twine("[{\"directory\":\"") + Directory + "\"," +
- "\"command\":\"" + Command + "\","
- "\"file\":\"" + FileName + "\"}]").str(), ErrorMessage);
- EXPECT_EQ(Directory, FoundCommand.Directory) << ErrorMessage;
-}
-
-TEST(FindCompileArgsInJsonDatabase, FindsEntry) {
- llvm::StringRef Directory("directory");
- llvm::StringRef FileName("file");
- llvm::StringRef Command("command");
- std::string JsonDatabase = "[";
- for (int I = 0; I < 10; ++I) {
- if (I > 0) JsonDatabase += ",";
- JsonDatabase += (llvm::Twine(
- "{\"directory\":\"") + Directory + llvm::Twine(I) + "\"," +
- "\"command\":\"" + Command + llvm::Twine(I) + "\","
- "\"file\":\"" + FileName + llvm::Twine(I) + "\"}").str();
- }
- JsonDatabase += "]";
- std::string ErrorMessage;
- CompileCommand FoundCommand = FindCompileArgsInJsonDatabase(
- "file4", JsonDatabase, ErrorMessage);
- EXPECT_EQ("directory4", FoundCommand.Directory) << ErrorMessage;
- ASSERT_EQ(1u, FoundCommand.CommandLine.size()) << ErrorMessage;
- EXPECT_EQ("command4", FoundCommand.CommandLine[0]) << ErrorMessage;
-}
-
-} // end namespace tooling
-} // end namespace clang
-
diff --git a/www/CheckerNotes.html b/www/CheckerNotes.html
deleted file mode 100644
index 523048d..0000000
--- a/www/CheckerNotes.html
+++ /dev/null
@@ -1,9 +0,0 @@
-<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
-<html>
-<head>
-<title>Static Analysis</title>
-<meta http-equiv="REFRESH" content="0;url=http://clang.llvm.org/StaticAnalysis.html"></HEAD>
-<BODY>
-This page has relocated: <a href="http://clang.llvm.org/StaticAnalysis.html">http://clang.llvm.org/StaticAnalysis.html</a>.
-</BODY>
-</HTML>
diff --git a/www/StaticAnalysis.html b/www/StaticAnalysis.html
deleted file mode 100644
index a701c0ff0..0000000
--- a/www/StaticAnalysis.html
+++ /dev/null
@@ -1,21 +0,0 @@
-<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
- "http://www.w3.org/TR/html4/strict.dtd">
-<html>
-<head>
- <meta HTTP-EQUIV="REFRESH" content="0; url=http://clang-analyzer.llvm.org">
- <title>LLVM/Clang Static Analyzer</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">
-
-<p>This page has moved: <a href="http://clang-analyzer.llvm.org">clang.analyzer.llvm.org</a>.</p>
-
-</div>
-</body>
-</html>
-
diff --git a/www/StaticAnalysisUsage.html b/www/StaticAnalysisUsage.html
deleted file mode 100644
index a701c0ff0..0000000
--- a/www/StaticAnalysisUsage.html
+++ /dev/null
@@ -1,21 +0,0 @@
-<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
- "http://www.w3.org/TR/html4/strict.dtd">
-<html>
-<head>
- <meta HTTP-EQUIV="REFRESH" content="0; url=http://clang-analyzer.llvm.org">
- <title>LLVM/Clang Static Analyzer</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">
-
-<p>This page has moved: <a href="http://clang-analyzer.llvm.org">clang.analyzer.llvm.org</a>.</p>
-
-</div>
-</body>
-</html>
-
diff --git a/www/analyzer/latest_checker.html.incl b/www/analyzer/latest_checker.html.incl
index 99151a8..76b88dd 100644
--- a/www/analyzer/latest_checker.html.incl
+++ b/www/analyzer/latest_checker.html.incl
@@ -1 +1 @@
-<b><a href="/checker/checker-256.tar.bz2">checker-256.tar.bz2</a></b> (built April 13, 2011)
+<b><a href="/checker/checker-257.tar.bz2">checker-257.tar.bz2</a></b> (built May 25, 2011)
diff --git a/www/analyzer/release_notes.html b/www/analyzer/release_notes.html
index 163e84f..4a568f5 100644
--- a/www/analyzer/release_notes.html
+++ b/www/analyzer/release_notes.html
@@ -15,9 +15,22 @@
<h1>Release notes for <tt>checker-XXX</tt> builds</h1>
+<h4 id="checker_257">checker-257</h4>
+
+<p><b>built:</b>May 25, 2011<br>
+<b>download:</b> <a href="/checker/checker-257.tar.bz2">checker-257.tar.bz2</a></p>
+<p><b>highlights:</b></p>
+
+<ul>
+ <li>The analyzer is now far more aggressive with checking conformance with Core Foundation conventions. Any function that returns a CF type must now obey the Core Foundation naming conventions, or use the <a href="/annotations.html#attr_cf_returns_retained">cf_returns_retained</a> or <a href="/annotations.html#attr_cf_returns_not_retained">cf_returns_not_retained</a> annotations.</li>
+ <li>Fixed a serious regression where the analyzer would not analyze Objective-C methods in class extensions.</li>
+ <li>Misc. bug fixes to improve analyzer precision.
+ </li>
+</ul>
+
<h4 id="checker_256">checker-256</h4>
-<p><b>built:</b> April 13, 2011<br>
+<p><b>built:</b>April 13, 2011<br>
<b>download:</b> <a href="/checker/checker-256.tar.bz2">checker-256.tar.bz2</a></p>
<p><b>highlights:</b></p>
diff --git a/www/clang-tutorial.html b/www/clang-tutorial.html
deleted file mode 100644
index 0e17046..0000000
--- a/www/clang-tutorial.html
+++ /dev/null
@@ -1,56 +0,0 @@
-<!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 &lt;&lt; D-&gt;getNameAsString()
- &lt;&lt; '\n';
- return false;
-}
-</pre>
-
- <p>Walk and print base classes of a class:</p>
- <pre>
-for(CXXRecordDecl::base_class_iterator
- B = D-&gt;bases_begin(), BEnd = D-&gt;bases_end();
- B != BEnd; ++B) {
- QualType BaseType = B-&gt;getType();
- std::cout &lt;&lt; " " &lt;&lt; BaseType.getAsString()
- &lt;&lt; '\n';
-}
-</pre>
-
- <p>Retrieve the C++ class declaration from a base type:</p>
- <pre>
-if (const RecordType *RTy
- = BaseType-&gt;getAs&lt;RecordType&gt;()) {
- RecordDecl *Base = RTy-&gt;getDecl();
- if (CXXRecordDecl *BaseCXX
- = dyn_cast&lt;CXXRecordDecl&gt;(Base)) {
-
- }
-}
-</pre>
-</div>
-</body>
-</html>
diff --git a/www/comparison.html b/www/comparison.html
index dcf6220..a7d4d75 100644
--- a/www/comparison.html
+++ b/www/comparison.html
@@ -50,10 +50,8 @@
<ul>
<li>GCC supports languages that clang does not aim to, such as Java, Ada,
FORTRAN, etc.</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 has a few <a href="cxx_status.html">C++'0x features</a> that Clang
+ does not yet support.</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>
@@ -114,6 +112,9 @@
including support for a bytecode representation for intermediate code,
pluggable optimizers, link-time optimization support, Just-In-Time
compilation, ability to link in multiple code generators, etc.</li>
+ <li><a href="compatibility.html#c++">Clang's support for C++</a> is more
+ compliant than GCC's in many ways (e.g. conformant two phase name
+ lookup).</li>
</ul>
<!--=====================================================================-->
@@ -131,6 +132,8 @@
<p>Pro's of clang vs Elsa:</p>
<ul>
+ <li>Clang's C and C++ support is far more mature and practically useful than
+ Elsa's, and includes many C++'0x features.</li>
<li>The Elsa community is extremely small and major development work seems
to have ceased in 2005. Work continued to be used by other small
projects (e.g. Oink), but Oink is apparently dead now too. Clang has a
@@ -157,12 +160,6 @@
<li>Elsa does not support native code generation.</li>
</ul>
- <p>Note that there is a fork of Elsa known as "Pork". It addresses some of
- these shortcomings by loosely integrating a preprocessor. This allows it
- to map from a source location in the AST to the original position before
- preprocessing, providing it better support for static analysis and
- refactoring. Note that Pork is in stasis now too.</p>
-
<!--=====================================================================-->
<h2><a name="pcc">Clang vs PCC (Portable C Compiler)</a></h2>
diff --git a/www/compatibility.html b/www/compatibility.html
index aa6a39d..b68a766 100644
--- a/www/compatibility.html
+++ b/www/compatibility.html
@@ -459,13 +459,15 @@ int main() {
<p>Clang complains:
-<pre> <b>my_file.cpp:2:10: <span class="error">error:</span> use of undeclared identifier 'Multiply'</b>
+<pre> <b>my_file.cpp:2:10: <span class="error">error:</span> call to function 'Multiply' that is neither visible in the template definition nor found by argument dependent lookup</b>
return Multiply(x, x);
<span class="caret"> ^</span>
-
<b>my_file.cpp:10:3: <span class="note">note:</span> in instantiation of function template specialization 'Squared&lt;int&gt;' requested here</b>
Squared(5);
<span class="caret"> ^</span>
+ <b>my_file.cpp:5:5: <span class="note">note:</span> 'Multiply' should be declared prior to the call site</b>
+ int Multiply(int x, int y) {
+ <span class="caret"> ^</span>
</pre>
<p>The C++ standard says that unqualified names like <q>Multiply</q>
@@ -516,15 +518,17 @@ void Use() {
Dump(ns::Data());
}</pre>
-<p>Again, Clang complains about not finding a matching function:</p>
+<p>Again, Clang complains:</p>
-<pre>
-<b>my_file.cpp:5:13: <span class="error">error:</span> invalid operands to binary expression ('ostream' (aka 'basic_ostream&lt;char&gt;') and 'ns::Data const')</b>
- std::cout &lt;&lt; value &lt;&lt; "\n";
- <span class="caret">~~~~~~~~~ ^ ~~~~~</span>
-<b>my_file.cpp:17:3: <span class="note">note:</span> in instantiation of function template specialization 'Dump&lt;ns::Data&gt;' requested here</b>
- Dump(ns::Data());
- <span class="caret">^</span>
+<pre> <b>my_file2.cpp:5:13: <span class="error">error:</span> call to function 'operator&lt;&lt;' that is neither visible in the template definition nor found by argument dependent lookup</b>
+ std::cout &lt;&lt; value &lt;&lt; "\n";
+ <span class="caret"> ^</span>
+ <b>my_file2.cpp:17:3: <span class="error">note:</span> in instantiation of function template specialization 'Dump&lt;ns::Data&gt;' requested here</b>
+ Dump(ns::Data());
+ <span class="caret"> ^</span>
+ <b>my_file2.cpp:12:15: <span class="error">note:</span> 'operator&lt;&lt;' should be declared prior to the call site or in namespace 'ns'</b>
+ std::ostream&amp; operator&lt;&lt;(std::ostream&amp; out, ns::Data data) {
+ <span class="caret"> ^</span>
</pre>
<p>Just like before, unqualified lookup didn't find any declarations
diff --git a/www/cxx_status.html b/www/cxx_status.html
index 5545a81..5998de8 100644
--- a/www/cxx_status.html
+++ b/www/cxx_status.html
@@ -25,7 +25,7 @@
<!--*************************************************************************-->
<h1>C++ and C++'0x Support in Clang</h1>
<!--*************************************************************************-->
-<p>Last updated: $Date: 2011-05-01 09:04:31 +0200 (Sun, 01 May 2011) $</p>
+<p>Last updated: $Date: 2011-05-06 00:07:51 +0200 (Fri, 06 May 2011) $</p>
<ul>
<li><a href="#projects">Projects Building with Clang</a></li>
@@ -213,7 +213,7 @@ welcome!</p>
<td class="complete" align="center">&#x2713;</td>
<td class="complete" align="center">&#x2713;</td>
<td class="advanced" align="center"></td>
- <td class="na">N/A</td>
+ <td class="advanced" align="center"></td>
<td>7.1.6.2</td>
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2343.pdf">N2343</a>
<a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2003/n1478.pdf">N1478</a>
@@ -460,14 +460,13 @@ welcome!</p>
</tr>
<tr>
<td>template aliases</td>
- <td class="basic"></td>
- <td class="basic"></td>
- <td class="basic"></td>
- <td></td>
+ <td class="complete" align="center">&#x2713;</td>
+ <td class="complete" align="center">&#x2713;</td>
+ <td class="complete" align="center">&#x2713;</td>
+ <td class="complete" align="center">&#x2713;</td>
<td>7.1.3, 14.6.7</td>
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2003/n1489.pdf">N1489</a>
<a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2258.pdf">N2258</a>
- Only non-template type aliases implemented
</td>
</tr>
<tr>
@@ -589,7 +588,7 @@ welcome!</p>
<td class="complete" align="center">&#x2713;</td>
<td class="complete" align="center">&#x2713;</td>
<td class="complete" align="center">&#x2713;</td>
- <td class="basic"></td>
+ <td class="na">N/A</td>
<td>8.3.5</td>
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2445.html">N2445</a></td>
</tr>
diff --git a/www/diagnostics.html b/www/diagnostics.html
index 4f7d025..48d222a 100644
--- a/www/diagnostics.html
+++ b/www/diagnostics.html
@@ -2,7 +2,7 @@
"http://www.w3.org/TR/html4/strict.dtd">
<html>
<head>
- <META http-equiv="Content-Type" content="text/html; charset=ISO-8859-1" />
+ <meta http-equiv="content-type" content="text/html; charset=iso-8859-1">
<title>Clang - Expressive Diagnostics</title>
<link type="text/css" rel="stylesheet" href="menu.css" />
<link type="text/css" rel="stylesheet" href="content.css" />
@@ -34,10 +34,18 @@ that embed Clang and extract equivalent information through internal APIs.-->
<h2>Column Numbers and Caret Diagnostics</h2>
<p>First, all diagnostics produced by clang include full column number
-information, and use this to print "caret diagnostics". This is a feature
-provided by many commercial compilers, but is generally missing from open source
+information. The clang command-line compiler driver uses this information
+to print "caret diagnostics".
+(IDEs can use the information to display in-line error markup.)
+Precise error location in the source is a feature provided by many commercial
+compilers, but is generally missing from open source
compilers. This is nice because it makes it very easy to understand exactly
-what is wrong in a particular piece of code, an example is:</p>
+what is wrong in a particular piece of code</p>
+
+<p>The caret (the blue "^" character) exactly shows where the problem is, even
+inside of a string. This makes it really easy to jump to the problem and
+helps when multiple instances of the same character occur on a line. (We'll
+revisit this more in following examples.)</p>
<pre>
$ <b>gcc-4.2 -fsyntax-only -Wformat format-strings.c</b>
@@ -48,17 +56,18 @@ what is wrong in a particular piece of code, an example is:</p>
<font color="blue"> ^</font>
</pre>
-<p>The caret (the blue "^" character) exactly shows where the problem is, even
-inside of the string. This makes it really easy to jump to the problem and
-helps when multiple instances of the same character occur on a line. We'll
-revisit this more in following examples.</p>
-
<h2>Range Highlighting for Related Text</h2>
<p>Clang captures and accurately tracks range information for expressions,
statements, and other constructs in your program and uses this to make
-diagnostics highlight related information. For example, here's a somewhat
-nonsensical example to illustrate this:</p>
+diagnostics highlight related information. In the following somewhat
+nonsensical example you can see that you don't even need to see the original source code to
+understand what is wrong based on the Clang error. Because clang prints a
+caret, you know exactly <em>which</em> plus it is complaining about. The range
+information highlights the left and right side of the plus which makes it
+immediately obvious what the compiler is talking about.
+Range information is very useful for
+cases involving precedence issues and many other cases.</p>
<pre>
$ <b>gcc-4.2 -fsyntax-only t.c</b>
@@ -69,21 +78,19 @@ nonsensical example to illustrate this:</p>
<font color="blue"> ~~~~~~~~~~~~~~ ^ ~~~~~</font>
</pre>
-<p>Here you can see that you don't even need to see the original source code to
-understand what is wrong based on the Clang error: Because clang prints a
-caret, you know exactly <em>which</em> plus it is complaining about. The range
-information highlights the left and right side of the plus which makes it
-immediately obvious what the compiler is talking about, which is very useful for
-cases involving precedence issues and many other cases.</p>
-
<h2>Precision in Wording</h2>
<p>A detail is that we have tried really hard to make the diagnostics that come
out of clang contain exactly the pertinent information about what is wrong and
why. In the example above, we tell you what the inferred types are for
the left and right hand sides, and we don't repeat what is obvious from the
-caret (that this is a "binary +"). Many other examples abound, here is a simple
-one:</p>
+caret (e.g., that this is a "binary +").</p>
+
+<p>Many other examples abound. In the following example, not only do we tell you that there is a problem with the *
+and point to it, we say exactly why and tell you what the type is (in case it is
+a complicated subexpression, such as a call to an overloaded function). This
+sort of attention to detail makes it much easier to understand and fix problems
+quickly.</p>
<pre>
$ <b>gcc-4.2 -fsyntax-only t.c</b>
@@ -94,12 +101,6 @@ one:</p>
<font color="blue"> ^~~~~~~~</font>
</pre>
-<p>In this example, not only do we tell you that there is a problem with the *
-and point to it, we say exactly why and tell you what the type is (in case it is
-a complicated subexpression, such as a call to an overloaded function). This
-sort of attention to detail makes it much easier to understand and fix problems
-quickly.</p>
-
<h2>No Pretty Printing of Expressions in Diagnostics</h2>
<p>Since Clang has range highlighting, it never needs to pretty print your code
@@ -127,8 +128,10 @@ typename in diagnostics. However, sometimes very simple typedefs can wrap
trivial types and it is important to strip off the typedef to understand what
is going on. Clang aims to handle both cases well.<p>
-<p>For example, here is an example that shows where it is important to preserve
-a typedef in C:</p>
+<p>The following example shows where it is important to preserve
+a typedef in C. Here the type printed by GCC isn't even valid, but if the error
+were about a very long and complicated type (as often happens in C++) the error
+message would be ugly just because it was long and hard to read.</p>
<pre>
$ <b>gcc-4.2 -fsyntax-only t.c</b>
@@ -139,10 +142,9 @@ a typedef in C:</p>
<font color="blue"> ~~~~~~~~^~</font>
</pre>
-<p>Here the type printed by GCC isn't even valid, but if the error were about a
-very long and complicated type (as often happens in C++) the error message would
-be ugly just because it was long and hard to read. Here's an example where it
-is useful for the compiler to expose underlying details of a typedef:</p>
+<p>The following example shows where it is useful for the compiler to expose
+underlying details of a typedef. If the user was somehow confused about how the
+system "pid_t" typedef is defined, Clang helpfully displays it with "aka".</p>
<pre>
$ <b>gcc-4.2 -fsyntax-only t.c</b>
@@ -153,9 +155,6 @@ is useful for the compiler to expose underlying details of a typedef:</p>
<font color="blue"> ~~~~~ ^</font>
</pre>
-<p>If the user was somehow confused about how the system "pid_t" typedef is
-defined, Clang helpfully displays it with "aka".</p>
-
<p>In C++, type preservation includes retaining any qualification written into type names. For example, if we take a small snippet of code such as:
<blockquote>
@@ -205,8 +204,10 @@ in source code. When Clang produces a diagnostic about a particular
problem that it can work around (e.g., non-standard or redundant
syntax, missing keywords, common mistakes, etc.), it may also provide
specific guidance in the form of a code transformation to correct the
-problem. For example, here Clang warns about the use of a GCC
-extension that has been considered obsolete since 1993:</p>
+problem. In the following example, Clang warns about the use of a GCC
+extension that has been considered obsolete since 1993. The underlined
+code should be removed, then replaced with the code below the
+caret line (".x =" or ".y =", respectively).</p>
<pre>
$ <b>clang t.c</b>
@@ -220,11 +221,12 @@ extension that has been considered obsolete since 1993:</p>
<font color="darkgreen">.y = </font>
</pre>
-<p>The underlined code should be removed, then replaced with the code below the
-caret line (".x =" or ".y =", respectively). "Fix-it" hints are most useful for
+<p>"Fix-it" hints are most useful for
working around common user errors and misconceptions. For example, C++ users
commonly forget the syntax for explicit specialization of class templates,
-as in the following error:</p>
+as in the error in the following example. Again, after describing the problem,
+Clang provides the fix--add <code>template&lt;&gt;</code>--as part of the
+diagnostic.<p>
<pre>
$ <b>clang t.cpp</b>
@@ -234,14 +236,14 @@ as in the following error:</p>
<font color="darkgreen">template&lt;&gt; </font>
</pre>
-<p>Again, after describing the problem, Clang provides the fix--add <code>template&lt;&gt;</code>--as part of the diagnostic.<p>
-
<h2>Automatic Macro Expansion</h2>
<p>Many errors happen in macros that are sometimes deeply nested. With
traditional compilers, you need to dig deep into the definition of the macro to
-understand how you got into trouble. Here's a simple example that shows how
-Clang helps you out:</p>
+understand how you got into trouble. The following simple example shows how
+Clang helps you out by automatically printing instantiation information and
+nested range information for diagnostics as they are instantiated through macros
+and also shows how some of the other pieces work in a bigger example.</p>
<pre>
$ <b>gcc-4.2 -fsyntax-only t.c</b>
@@ -256,10 +258,7 @@ Clang helps you out:</p>
<font color="blue"> ~~~ ^ ~~~</font>
</pre>
-<p>This shows how clang automatically prints instantiation information and
-nested range information for diagnostics as they are instantiated through macros
-and also shows how some of the other pieces work in a bigger example. Here's
-another real world warning that occurs in the "window" Unix package (which
+<p>Here's another real world warning that occurs in the "window" Unix package (which
implements the "wwopen" class of APIs):</p>
<pre>
@@ -275,14 +274,19 @@ implements the "wwopen" class of APIs):</p>
<font color="blue"> ^</font>
</pre>
-<p>In practice, we've found that this is actually more useful in multiply nested
+<p>In practice, we've found that Clang's treatment of macros is actually more useful in multiply nested
macros that in simple ones.</p>
<h2>Quality of Implementation and Attention to Detail</h2>
<p>Finally, we have put a lot of work polishing the little things, because
-little things add up over time and contribute to a great user experience. Three
-examples are:</p>
+little things add up over time and contribute to a great user experience.</p>
+
+<p>The following example shows a trivial little tweak, where we tell you to put the semicolon at
+the end of the line that is missing it (line 4) instead of at the beginning of
+the following line (line 5). This is particularly important with fixit hints
+and caret diagnostics, because otherwise you don't get the important context.
+</p>
<pre>
$ <b>gcc-4.2 t.c</b>
@@ -295,11 +299,9 @@ examples are:</p>
<font color="blue"> ;</font>
</pre>
-<p>This shows a trivial little tweak, where we tell you to put the semicolon at
-the end of the line that is missing it (line 4) instead of at the beginning of
-the following line (line 5). This is particularly important with fixit hints
-and caret diagnostics, because otherwise you don't get the important context.
-</p>
+<p>The following example shows much better error recovery than GCC. The message coming out
+of GCC is completely useless for diagnosing the problem. Clang tries much harder
+and produces a much more useful diagnosis of the problem.</p>
<pre>
$ <b>gcc-4.2 t.c</b>
@@ -310,9 +312,8 @@ and caret diagnostics, because otherwise you don't get the important context.
<font color="blue">^</font>
</pre>
-<p>This shows an example of much better error recovery. The message coming out
-of GCC is completely useless for diagnosing the problem, Clang tries much harder
-and produces a much more useful diagnosis of the problem.</p>
+<p>The following example shows that we recover from the simple case of
+forgetting a ; after a struct definition much better than GCC.</p>
<pre>
$ <b>cat t.cc</b>
@@ -338,9 +339,6 @@ and produces a much more useful diagnosis of the problem.</p>
<font color="blue"> ;</font>
</pre>
-<p>This shows that we recover from the simple case of forgetting a ; after
-a struct definition much better than GCC.</p>
-
<p>While each of these details is minor, we feel that they all add up to provide
a much more polished experience.</p>
diff --git a/www/distclang_status.html b/www/distclang_status.html
deleted file mode 100644
index 26ba314..0000000
--- a/www/distclang_status.html
+++ /dev/null
@@ -1,30 +0,0 @@
-<!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 - Distributed Compilation Support</title>
- <link type="text/css" rel="stylesheet" href="menu.css" />
- <link type="text/css" rel="stylesheet" href="content.css" />
- <style type="text/css">
-</style>
-</head>
-<body>
-
-<!--#include virtual="menu.html.incl"-->
-
-<div id="content">
-
-<!--*************************************************************************-->
-<h1>Distributed Compilation Support in Clang</h1>
-<!--*************************************************************************-->
-
-<p>
-This page tracks the status of Distributed Compilation support in Clang.<br>
-Currently some basic features are working but the code is under heavy
-development. </p>
-
-
-</div>
-</body>
-</html>
diff --git a/www/features.html b/www/features.html
index 869d0d8..9e342ea 100644
--- a/www/features.html
+++ b/www/features.html
@@ -232,7 +232,6 @@ Currently, clang is divided into the following libraries and tool:
<li><b>librewrite</b> - Editing of text buffers (important for code rewriting
transformation, like refactoring).</li>
<li><b>libanalysis</b> - Static analysis support.</li>
-<li><b><a href="docs/libIndex.html">libindex</a></b> - Cross-translation-unit infrastructure and indexing support.</li>
<li><b>clang</b> - A driver program, client of the libraries at various
levels.</li>
</ul>
diff --git a/www/libstdc++4.4-clang0x.patch b/www/libstdc++4.4-clang0x.patch
index 8b9916d..db43583 100644
--- a/www/libstdc++4.4-clang0x.patch
+++ b/www/libstdc++4.4-clang0x.patch
@@ -6,6 +6,18 @@ standard headers.
This patch is offered under the same modified GPLv3 as libstdc++-4.4.
+diff -ur a/bits/forward_list.h b/bits/forward_list.h
+--- a/bits/forward_list.h 2011-03-15 14:49:05.000000000 -0700
++++ b/bits/forward_list.h 2011-05-02 23:51:33.000000000 -0700
+@@ -983,7 +983,7 @@
+ * function.
+ */
+ void
+- swap(forward_list&& __list)
++ swap(forward_list& __list)
+ { _Node_base::swap(this->_M_impl._M_head, __list._M_impl._M_head); }
+
+ /**
diff -ur a/bits/move.h b/bits/move.h
--- a/bits/move.h 2011-03-15 14:49:05.000000000 -0700
+++ b/bits/move.h 2011-03-29 10:33:39.000000000 -0700
@@ -46,6 +58,67 @@ diff -ur a/bits/move.h b/bits/move.h
_GLIBCXX_END_NAMESPACE
+diff -ur a/bits/shared_ptr.h b/bits/shared_ptr.h
+--- a/bits/shared_ptr.h 2011-03-15 14:49:05.000000000 -0700
++++ b/bits/shared_ptr.h 2011-03-31 16:40:45.000000000 -0700
+@@ -833,7 +833,7 @@
+ { return _M_refcount._M_get_use_count(); }
+
+ void
+- swap(__shared_ptr<_Tp, _Lp>&& __other) // never throws
++ swap(__shared_ptr<_Tp, _Lp>& __other) // never throws
+ {
+ std::swap(_M_ptr, __other._M_ptr);
+ _M_refcount._M_swap(__other._M_refcount);
+@@ -943,16 +943,6 @@
+ swap(__shared_ptr<_Tp, _Lp>& __a, __shared_ptr<_Tp, _Lp>& __b)
+ { __a.swap(__b); }
+
+- template<typename _Tp, _Lock_policy _Lp>
+- inline void
+- swap(__shared_ptr<_Tp, _Lp>&& __a, __shared_ptr<_Tp, _Lp>& __b)
+- { __a.swap(__b); }
+-
+- template<typename _Tp, _Lock_policy _Lp>
+- inline void
+- swap(__shared_ptr<_Tp, _Lp>& __a, __shared_ptr<_Tp, _Lp>&& __b)
+- { __a.swap(__b); }
+-
+ // 2.2.3.9 shared_ptr casts
+ /** @warning The seemingly equivalent
+ * <code>shared_ptr<_Tp, _Lp>(static_cast<_Tp*>(__r.get()))</code>
+@@ -1372,16 +1362,6 @@
+ swap(shared_ptr<_Tp>& __a, shared_ptr<_Tp>& __b)
+ { __a.swap(__b); }
+
+- template<typename _Tp>
+- inline void
+- swap(shared_ptr<_Tp>&& __a, shared_ptr<_Tp>& __b)
+- { __a.swap(__b); }
+-
+- template<typename _Tp>
+- inline void
+- swap(shared_ptr<_Tp>& __a, shared_ptr<_Tp>&& __b)
+- { __a.swap(__b); }
+-
+ // 20.8.13.2.10 shared_ptr casts.
+ template<typename _Tp, typename _Tp1>
+ inline shared_ptr<_Tp>
+diff -ur a/bits/stl_bvector.h b/bits/stl_bvector.h
+--- a/bits/stl_bvector.h 2011-03-15 14:49:05.000000000 -0700
++++ b/bits/stl_bvector.h 2011-05-02 23:34:46.000000000 -0700
+@@ -743,11 +743,7 @@
+ }
+
+ void
+-#ifdef __GXX_EXPERIMENTAL_CXX0X__
+- swap(vector&& __x)
+-#else
+ swap(vector& __x)
+-#endif
+ {
+ std::swap(this->_M_impl._M_start, __x._M_impl._M_start);
+ std::swap(this->_M_impl._M_finish, __x._M_impl._M_finish);
diff -ur a/bits/stl_deque.h b/bits/stl_deque.h
--- a/bits/stl_deque.h 2011-03-15 14:49:05.000000000 -0700
+++ b/bits/stl_deque.h 2011-03-29 10:33:39.000000000 -0700
@@ -253,6 +326,27 @@ diff -ur a/bits/stl_pair.h b/bits/stl_pair.h
{
using std::swap;
swap(first, __p.first);
+diff -ur a/bits/stl_queue.h b/bits/stl_queue.h
+--- a/bits/stl_queue.h 2011-03-15 14:49:05.000000000 -0700
++++ b/bits/stl_queue.h 2011-05-02 23:36:15.000000000 -0700
+@@ -249,7 +249,7 @@
+
+ #ifdef __GXX_EXPERIMENTAL_CXX0X__
+ void
+- swap(queue&& __q)
++ swap(queue& __q)
+ { c.swap(__q.c); }
+ #endif
+ };
+@@ -550,7 +550,7 @@
+
+ #ifdef __GXX_EXPERIMENTAL_CXX0X__
+ void
+- swap(priority_queue&& __pq)
++ swap(priority_queue& __pq)
+ {
+ using std::swap;
+ c.swap(__pq.c);
diff -ur a/bits/stl_set.h b/bits/stl_set.h
--- a/bits/stl_set.h 2011-03-15 14:49:05.000000000 -0700
+++ b/bits/stl_set.h 2011-03-29 10:33:39.000000000 -0700
@@ -268,6 +362,18 @@ diff -ur a/bits/stl_set.h b/bits/stl_set.h
{ _M_t.swap(__x._M_t); }
// insert/erase
+diff -ur a/bits/stl_stack.h b/bits/stl_stack.h
+--- a/bits/stl_stack.h 2011-03-15 14:49:05.000000000 -0700
++++ b/bits/stl_stack.h 2011-05-02 23:36:36.000000000 -0700
+@@ -213,7 +213,7 @@
+
+ #ifdef __GXX_EXPERIMENTAL_CXX0X__
+ void
+- swap(stack&& __s)
++ swap(stack& __s)
+ { c.swap(__s.c); }
+ #endif
+ };
diff -ur a/bits/stl_tree.h b/bits/stl_tree.h
--- a/bits/stl_tree.h 2011-03-15 14:49:05.000000000 -0700
+++ b/bits/stl_tree.h 2011-03-29 10:33:39.000000000 -0700
@@ -310,6 +416,46 @@ diff -ur a/bits/stl_vector.h b/bits/stl_vector.h
{
std::swap(this->_M_impl._M_start, __x._M_impl._M_start);
std::swap(this->_M_impl._M_finish, __x._M_impl._M_finish);
+diff -ur a/bits/unique_ptr.h b/bits/unique_ptr.h
+--- a/bits/unique_ptr.h 2011-03-15 14:49:05.000000000 -0700
++++ b/bits/unique_ptr.h 2011-03-31 16:40:45.000000000 -0700
+@@ -204,7 +204,7 @@
+ }
+
+ void
+- swap(unique_ptr&& __u)
++ swap(unique_ptr& __u)
+ {
+ using std::swap;
+ swap(_M_t, __u._M_t);
+@@ -350,7 +350,7 @@
+ void reset(_Up) = delete;
+
+ void
+- swap(unique_ptr&& __u)
++ swap(unique_ptr& __u)
+ {
+ using std::swap;
+ swap(_M_t, __u._M_t);
+@@ -389,18 +389,6 @@
+ unique_ptr<_Tp, _Tp_Deleter>& __y)
+ { __x.swap(__y); }
+
+- template<typename _Tp, typename _Tp_Deleter>
+- inline void
+- swap(unique_ptr<_Tp, _Tp_Deleter>&& __x,
+- unique_ptr<_Tp, _Tp_Deleter>& __y)
+- { __x.swap(__y); }
+-
+- template<typename _Tp, typename _Tp_Deleter>
+- inline void
+- swap(unique_ptr<_Tp, _Tp_Deleter>& __x,
+- unique_ptr<_Tp, _Tp_Deleter>&& __y)
+- { __x.swap(__y); }
+-
+ template<typename _Tp, typename _Tp_Deleter,
+ typename _Up, typename _Up_Deleter>
+ inline bool
diff -ur a/exception_ptr.h b/exception_ptr.h
--- a/exception_ptr.h 2011-03-15 14:49:08.000000000 -0700
+++ b/exception_ptr.h 2011-03-29 10:33:39.000000000 -0700
@@ -367,3 +513,96 @@ diff -ur a/ext/vstring.h b/ext/vstring.h
{ this->_M_swap(__s); }
// String operations:
+diff -ur a/tr1_impl/hashtable b/tr1_impl/hashtable
+--- a/tr1_impl/hashtable 2011-03-15 14:49:07.000000000 -0700
++++ b/tr1_impl/hashtable 2011-05-02 23:41:55.000000000 -0700
+@@ -225,11 +225,7 @@
+
+ ~_Hashtable();
+
+-#ifdef _GLIBCXX_INCLUDE_AS_CXX0X
+- void swap(_Hashtable&&);
+-#else
+ void swap(_Hashtable&);
+-#endif
+
+ // Basic container operations
+ iterator
+@@ -732,11 +728,7 @@
+ void
+ _Hashtable<_Key, _Value, _Allocator, _ExtractKey, _Equal,
+ _H1, _H2, _Hash, _RehashPolicy, __chc, __cit, __uk>::
+-#ifdef _GLIBCXX_INCLUDE_AS_CXX0X
+- swap(_Hashtable&& __x)
+-#else
+ swap(_Hashtable& __x)
+-#endif
+ {
+ // The only base class with member variables is hash_code_base. We
+ // define _Hash_code_base::_M_swap because different specializations
+diff -ur a/tuple b/tuple
+--- a/tuple 2011-03-15 14:49:07.000000000 -0700
++++ b/tuple 2011-05-02 23:33:23.000000000 -0700
+@@ -77,7 +77,7 @@
+ _Head& _M_head() { return *this; }
+ const _Head& _M_head() const { return *this; }
+
+- void _M_swap_impl(_Head&&) { /* no-op */ }
++ void _M_swap_impl(_Head&) { /* no-op */ }
+ };
+
+ template<std::size_t _Idx, typename _Head>
+@@ -97,7 +97,7 @@
+ const _Head& _M_head() const { return _M_head_impl; }
+
+ void
+- _M_swap_impl(_Head&& __h)
++ _M_swap_impl(_Head& __h)
+ {
+ using std::swap;
+ swap(__h, _M_head_impl);
+@@ -125,7 +125,7 @@
+ struct _Tuple_impl<_Idx>
+ {
+ protected:
+- void _M_swap_impl(_Tuple_impl&&) { /* no-op */ }
++ void _M_swap_impl(_Tuple_impl&) { /* no-op */ }
+ };
+
+ /**
+@@ -214,7 +214,7 @@
+
+ protected:
+ void
+- _M_swap_impl(_Tuple_impl&& __in)
++ _M_swap_impl(_Tuple_impl& __in)
+ {
+ _Base::_M_swap_impl(__in._M_head());
+ _Inherited::_M_swap_impl(__in._M_tail());
+@@ -292,7 +292,7 @@
+ }
+
+ void
+- swap(tuple&& __in)
++ swap(tuple& __in)
+ { _Inherited::_M_swap_impl(__in); }
+ };
+
+@@ -301,7 +301,7 @@
+ class tuple<>
+ {
+ public:
+- void swap(tuple&&) { /* no-op */ }
++ void swap(tuple&) { /* no-op */ }
+ };
+
+ /// tuple (2-element), with construction and assignment from a pair.
+@@ -394,7 +394,7 @@
+ }
+
+ void
+- swap(tuple&& __in)
++ swap(tuple& __in)
+ {
+ using std::swap;
+ swap(this->_M_head(), __in._M_head());
OpenPOWER on IntegriCloud